Add testcase for PR/24065.
[deliverable/binutils-gdb.git] / gdb / arc-tdep.c
index 657b1eb84f4e13764516e765b9a31477b6e14e3c..cd2762cb5cd61b654c4b7a38eaeae87d8638dd8c 100644 (file)
@@ -1,6 +1,6 @@
 /* Target dependent code for ARC arhitecture, for GDB.
 
-   Copyright 2005-2017 Free Software Foundation, Inc.
+   Copyright 2005-2019 Free Software Foundation, Inc.
    Contributed by Synopsys Inc.
 
    This file is part of GDB.
@@ -33,7 +33,7 @@
 
 /* ARC header files.  */
 #include "opcode/arc.h"
-#include "opcodes/arc-dis.h"
+#include "../opcodes/arc-dis.h"
 #include "arc-tdep.h"
 
 /* Standard headers.  */
@@ -145,6 +145,8 @@ static const char *const core_arcompact_register_names[] = {
   "lp_count", "reserved", "limm", "pcl",
 };
 
+static char *arc_disassembler_options = NULL;
+
 /* Functions are sorted in the order as they are used in the
    _initialize_arc_tdep (), which uses the same order as gdbarch.h.  Static
    functions are defined before the first invocation.  */
@@ -445,7 +447,7 @@ arc_insn_get_linear_next_pc (const struct arc_instruction &insn)
 static void
 arc_write_pc (struct regcache *regcache, CORE_ADDR new_pc)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch *gdbarch = regcache->arch ();
 
   if (arc_debug)
     debug_printf ("arc: Writing PC, new value=%s\n",
@@ -590,7 +592,8 @@ arc_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 static CORE_ADDR
 arc_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,
+                    struct value **args, CORE_ADDR sp,
+                    function_call_return_method return_method,
                     CORE_ADDR struct_addr)
 {
   if (arc_debug)
@@ -605,7 +608,7 @@ arc_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      value return?  If so, struct_addr is the address of the reserved space for
      the return structure to be written on the stack, and that address is
      passed to that function as a hidden first argument.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       /* Pass the return address in the first argument register.  */
       regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);
@@ -662,7 +665,7 @@ arc_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
          /* Note we don't use write_unsigned here, since that would convert
             the byte order, but we are already in the correct byte order.  */
-         regcache_cooked_write (regcache, arg_reg, data);
+         regcache->cooked_write (arg_reg, data);
 
          data += ARC_REGISTER_SIZE;
          total_space -= ARC_REGISTER_SIZE;
@@ -1012,7 +1015,7 @@ arc_is_in_prologue (struct gdbarch *gdbarch, const struct arc_instruction &insn,
        addr = pv_add_constant (regs[base_reg],
                                arc_insn_get_memory_offset (insn));
 
-      if (pv_area_store_would_trash (stack, addr))
+      if (stack->store_would_trash (addr))
        return false;
 
       if (insn.data_size_mode != ARC_SCALING_D)
@@ -1029,7 +1032,7 @@ arc_is_in_prologue (struct gdbarch *gdbarch, const struct arc_instruction &insn,
          else
            size = ARC_REGISTER_SIZE;
 
-         pv_area_store (stack, addr, size, store_value);
+         stack->store (addr, size, store_value);
        }
       else
        {
@@ -1038,16 +1041,15 @@ arc_is_in_prologue (struct gdbarch *gdbarch, const struct arc_instruction &insn,
              /* If this is a double store, than write N+1 register as well.  */
              pv_t store_value1 = regs[insn.operands[0].value];
              pv_t store_value2 = regs[insn.operands[0].value + 1];
-             pv_area_store (stack, addr, ARC_REGISTER_SIZE, store_value1);
-             pv_area_store (stack,
-                            pv_add_constant (addr, ARC_REGISTER_SIZE),
-                            ARC_REGISTER_SIZE, store_value2);
+             stack->store (addr, ARC_REGISTER_SIZE, store_value1);
+             stack->store (pv_add_constant (addr, ARC_REGISTER_SIZE),
+                           ARC_REGISTER_SIZE, store_value2);
            }
          else
            {
              pv_t store_value
                = pv_constant (arc_insn_get_operand_value (insn, 0));
-             pv_area_store (stack, addr, ARC_REGISTER_SIZE * 2, store_value);
+             stack->store (addr, ARC_REGISTER_SIZE * 2, store_value);
            }
        }
 
@@ -1134,7 +1136,7 @@ arc_is_in_prologue (struct gdbarch *gdbarch, const struct arc_instruction &insn,
 
       /* Assume that if the last register (closest to new SP) can be written,
         then it is possible to write all of them.  */
-      if (pv_area_store_would_trash (stack, new_sp))
+      if (stack->store_would_trash (new_sp))
        return false;
 
       /* Current store address.  */
@@ -1143,21 +1145,21 @@ arc_is_in_prologue (struct gdbarch *gdbarch, const struct arc_instruction &insn,
       if (is_fp_saved)
        {
          addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
-         pv_area_store (stack, addr, ARC_REGISTER_SIZE, regs[ARC_FP_REGNUM]);
+         stack->store (addr, ARC_REGISTER_SIZE, regs[ARC_FP_REGNUM]);
        }
 
       /* Registers are stored in backward order: from GP (R26) to R13.  */
       for (int i = ARC_R13_REGNUM + regs_saved - 1; i >= ARC_R13_REGNUM; i--)
        {
          addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
-         pv_area_store (stack, addr, ARC_REGISTER_SIZE, regs[i]);
+         stack->store (addr, ARC_REGISTER_SIZE, regs[i]);
        }
 
       if (is_blink_saved)
        {
          addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
-         pv_area_store (stack, addr, ARC_REGISTER_SIZE,
-                        regs[ARC_BLINK_REGNUM]);
+         stack->store (addr, ARC_REGISTER_SIZE,
+                       regs[ARC_BLINK_REGNUM]);
        }
 
       gdb_assert (pv_is_identical (addr, new_sp));
@@ -1269,9 +1271,7 @@ arc_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR entrypoint,
   pv_t regs[ARC_LAST_CORE_REGNUM + 1];
   for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
     regs[i] = pv_register (i, 0);
-  struct pv_area *stack = make_pv_area (ARC_SP_REGNUM,
-                                       gdbarch_addr_bit (gdbarch));
-  struct cleanup *back_to = make_cleanup_free_pv_area (stack);
+  pv_area stack (ARC_SP_REGNUM, gdbarch_addr_bit (gdbarch));
 
   CORE_ADDR current_prologue_end = entrypoint;
 
@@ -1288,7 +1288,7 @@ arc_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR entrypoint,
 
       /* If this instruction is in the prologue, fields in the cache will be
         updated, and the saved registers mask may be updated.  */
-      if (!arc_is_in_prologue (gdbarch, insn, regs, stack))
+      if (!arc_is_in_prologue (gdbarch, insn, regs, &stack))
        {
          /* Found an instruction that is not in the prologue.  */
          if (arc_debug)
@@ -1318,12 +1318,11 @@ arc_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR entrypoint,
       for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
        {
          CORE_ADDR offset;
-         if (pv_area_find_reg (stack, gdbarch, i, &offset))
+         if (stack.find_reg (gdbarch, i, &offset))
            cache->saved_regs[i].addr = offset;
        }
     }
 
-  do_cleanups (back_to);
   return current_prologue_end;
 }
 
@@ -1405,12 +1404,34 @@ arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
 int
 arc_delayed_print_insn (bfd_vma addr, struct disassemble_info *info)
 {
-  int (*print_insn) (bfd_vma, struct disassemble_info *);
-  /* exec_bfd may be null, if GDB is run without a target BFD file.  Opcodes
-     will handle NULL value gracefully.  */
-  print_insn = arc_get_disassembler (exec_bfd);
-  gdb_assert (print_insn != NULL);
-  return print_insn (addr, info);
+  /* Standard BFD "machine number" field allows libocodes disassembler to
+     distinguish ARC 600, 700 and v2 cores, however v2 encompasses both ARC EM
+     and HS, which have some difference between.  There are two ways to specify
+     what is the target core:
+     1) via the disassemble_info->disassembler_options;
+     2) otherwise libopcodes will use private (architecture-specific) ELF
+     header.
+
+     Using disassembler_options is preferable, because it comes directly from
+     GDBserver which scanned an actual ARC core identification info.  However,
+     not all GDBservers report core architecture, so as a fallback GDB still
+     should support analysis of ELF header.  The libopcodes disassembly code
+     uses the section to find the BFD and the BFD to find the ELF header,
+     therefore this function should set disassemble_info->section properly.
+
+     disassembler_options was already set by non-target specific code with
+     proper options obtained via gdbarch_disassembler_options ().
+
+     This function might be called multiple times in a sequence, reusing same
+     disassemble_info.  */
+  if ((info->disassembler_options == NULL) && (info->section == NULL))
+    {
+      struct obj_section *s = find_pc_section (addr);
+      if (s != NULL)
+       info->section = s->the_bfd_section;
+    }
+
+  return default_print_insn (addr, info);
 }
 
 /* Baremetal breakpoint instructions.
@@ -1530,7 +1551,7 @@ arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
 /* Dump the frame info.  Used for internal debugging only.  */
 
 static void
-arc_print_frame_cache (struct gdbarch *gdbarch, char *message,
+arc_print_frame_cache (struct gdbarch *gdbarch, const char *message,
                       struct arc_frame_cache *cache, int addresses_known)
 {
   debug_printf ("arc: frame_info %s\n", message);
@@ -1937,6 +1958,15 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
   return TRUE;
 }
 
+/* Implement the type_align gdbarch function.  */
+
+static ULONGEST
+arc_type_align (struct gdbarch *gdbarch, struct type *type)
+{
+  type = check_typedef (type);
+  return std::min<ULONGEST> (4, TYPE_LENGTH (type));
+}
+
 /* Implement the "init" gdbarch method.  */
 
 static struct gdbarch *
@@ -1962,7 +1992,7 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_int_bit (gdbarch, 32);
   set_gdbarch_long_bit (gdbarch, 32);
   set_gdbarch_long_long_bit (gdbarch, 64);
-  set_gdbarch_long_long_align_bit (gdbarch, 32);
+  set_gdbarch_type_align (gdbarch, arc_type_align);
   set_gdbarch_float_bit (gdbarch, 32);
   set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
   set_gdbarch_double_bit (gdbarch, 64);
@@ -2043,6 +2073,61 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (tdep->jb_pc >= 0)
     set_gdbarch_get_longjmp_target (gdbarch, arc_get_longjmp_target);
 
+  /* Disassembler options.  Enforce CPU if it was specified in XML target
+     description, otherwise use default method of determining CPU (ELF private
+     header).  */
+  if (info.target_desc != NULL)
+    {
+      const struct bfd_arch_info *tdesc_arch
+       = tdesc_architecture (info.target_desc);
+      if (tdesc_arch != NULL)
+       {
+         xfree (arc_disassembler_options);
+         /* FIXME: It is not really good to change disassembler options
+            behind the scene, because that might override options
+            specified by the user.  However as of now ARC doesn't support
+            `set disassembler-options' hence this code is the only place
+            where options are changed.  It also changes options for all
+            existing gdbarches, which also can be problematic, if
+            arc_gdbarch_init will start reusing existing gdbarch
+            instances.  */
+         /* Target description specifies a BFD architecture, which is
+            different from ARC cpu, as accepted by disassembler (and most
+            other ARC tools), because cpu values are much more fine grained -
+            there can be multiple cpu values per single BFD architecture.  As
+            a result this code should translate architecture to some cpu
+            value.  Since there is no info on exact cpu configuration, it is
+            best to use the most feature-rich CPU, so that disassembler will
+            recognize all instructions available to the specified
+            architecture.  */
+         switch (tdesc_arch->mach)
+           {
+           case bfd_mach_arc_arc601:
+             arc_disassembler_options = xstrdup ("cpu=arc601");
+             break;
+           case bfd_mach_arc_arc600:
+             arc_disassembler_options = xstrdup ("cpu=arc600");
+             break;
+           case bfd_mach_arc_arc700:
+             arc_disassembler_options = xstrdup ("cpu=arc700");
+             break;
+           case bfd_mach_arc_arcv2:
+             /* Machine arcv2 has three arches: ARCv2, EM and HS; where ARCv2
+                is treated as EM.  */
+             if (arc_arch_is_hs (tdesc_arch))
+               arc_disassembler_options = xstrdup ("cpu=hs38_linux");
+             else
+               arc_disassembler_options = xstrdup ("cpu=em4_fpuda");
+             break;
+           default:
+             arc_disassembler_options = NULL;
+             break;
+           }
+         set_gdbarch_disassembler_options (gdbarch,
+                                           &arc_disassembler_options);
+       }
+    }
+
   tdesc_use_registers (gdbarch, tdesc, tdesc_data);
 
   return gdbarch;
@@ -2061,7 +2146,7 @@ arc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
 /* Wrapper for "maintenance print arc" list of commands.  */
 
 static void
-maintenance_print_arc_command (char *args, int from_tty)
+maintenance_print_arc_command (const char *args, int from_tty)
 {
   cmd_show_list (maintenance_print_arc_list, from_tty, "");
 }
@@ -2070,7 +2155,7 @@ maintenance_print_arc_command (char *args, int from_tty)
    disassemble.  */
 
 static void
-dump_arc_instruction_command (char *args, int from_tty)
+dump_arc_instruction_command (const char *args, int from_tty)
 {
   struct value *val;
   if (args != NULL && strlen (args) > 0)
@@ -2086,9 +2171,6 @@ dump_arc_instruction_command (char *args, int from_tty)
   arc_insn_dump (insn);
 }
 
-/* Suppress warning from -Wmissing-prototypes.  */
-extern initialize_file_ftype _initialize_arc_tdep;
-
 void
 _initialize_arc_tdep (void)
 {
This page took 0.029301 seconds and 4 git commands to generate.