2011-02-21 Hui Zhu <teawater@gmail.com>
[deliverable/binutils-gdb.git] / gdb / solib-frv.c
index 5d2c9a12fc057c4b1abd7e93e78b0121512668f2..16455bef03f4801406a9f93599a8534f4090259a 100644 (file)
@@ -1,11 +1,12 @@
 /* Handle FR-V (FDPIC) shared libraries for GDB, the GNU Debugger.
-   Copyright (C) 2004, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2007, 2008, 2009, 2010, 2011
+   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 2 of the License, or
+   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,
@@ -14,9 +15,7 @@
    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, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
 #include "defs.h"
@@ -32,6 +31,7 @@
 #include "command.h"
 #include "gdbcmd.h"
 #include "elf/frv.h"
+#include "exceptions.h"
 
 /* Flag which indicates whether internal debug messages should be printed.  */
 static int solib_frv_debug;
@@ -98,6 +98,7 @@ struct int_elf32_fdpic_loadmap {
 static struct int_elf32_fdpic_loadmap *
 fetch_loadmap (CORE_ADDR ldmaddr)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
   struct ext_elf32_fdpic_loadmap ext_ldmbuf_partial;
   struct ext_elf32_fdpic_loadmap *ext_ldmbuf;
   struct int_elf32_fdpic_loadmap *int_ldmbuf;
@@ -114,7 +115,8 @@ fetch_loadmap (CORE_ADDR ldmaddr)
 
   /* Extract the version.  */
   version = extract_unsigned_integer (ext_ldmbuf_partial.version,
-                                      sizeof ext_ldmbuf_partial.version);
+                                      sizeof ext_ldmbuf_partial.version,
+                                     byte_order);
   if (version != 0)
     {
       /* We only handle version 0.  */
@@ -123,7 +125,11 @@ fetch_loadmap (CORE_ADDR ldmaddr)
 
   /* Extract the number of segments.  */
   nsegs = extract_unsigned_integer (ext_ldmbuf_partial.nsegs,
-                                    sizeof ext_ldmbuf_partial.nsegs);
+                                    sizeof ext_ldmbuf_partial.nsegs,
+                                   byte_order);
+
+  if (nsegs <= 0)
+    return NULL;
 
   /* Allocate space for the complete (external) loadmap.  */
   ext_ldmbuf_size = sizeof (struct ext_elf32_fdpic_loadmap)
@@ -156,13 +162,16 @@ fetch_loadmap (CORE_ADDR ldmaddr)
     {
       int_ldmbuf->segs[seg].addr
        = extract_unsigned_integer (ext_ldmbuf->segs[seg].addr,
-                                   sizeof (ext_ldmbuf->segs[seg].addr));
+                                   sizeof (ext_ldmbuf->segs[seg].addr),
+                                   byte_order);
       int_ldmbuf->segs[seg].p_vaddr
        = extract_unsigned_integer (ext_ldmbuf->segs[seg].p_vaddr,
-                                   sizeof (ext_ldmbuf->segs[seg].p_vaddr));
+                                   sizeof (ext_ldmbuf->segs[seg].p_vaddr),
+                                   byte_order);
       int_ldmbuf->segs[seg].p_memsz
        = extract_unsigned_integer (ext_ldmbuf->segs[seg].p_memsz,
-                                   sizeof (ext_ldmbuf->segs[seg].p_memsz));
+                                   sizeof (ext_ldmbuf->segs[seg].p_memsz),
+                                   byte_order);
     }
 
   xfree (ext_ldmbuf);
@@ -193,7 +202,7 @@ struct ext_link_map
   ext_ptr l_next, l_prev;      /* struct link_map *l_next, *l_prev; */
 };
 
-/* Link map info to include in an allocated so_list entry */
+/* Link map info to include in an allocated so_list entry */
 
 struct lm_info
   {
@@ -216,7 +225,7 @@ struct lm_info
        caching of the dynamic relocations could be dispensed with.  */
     asymbol **dyn_syms;
     arelent **dyn_relocs;
-    int dyn_reloc_count;       /* number of dynamic relocs.  */
+    int dyn_reloc_count;       /* Number of dynamic relocs.  */
 
   };
 
@@ -275,7 +284,7 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
          sym = *symbol_table++;
          if (strcmp (sym->name, symname) == 0)
            {
-             /* Bfd symbols are section relative. */
+             /* Bfd symbols are section relative.  */
              symaddr = sym->value + sym->section->vma;
              break;
            }
@@ -301,7 +310,7 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
          sym = *symbol_table++;
          if (strcmp (sym->name, symname) == 0)
            {
-             /* Bfd symbols are section relative. */
+             /* Bfd symbols are section relative.  */
              symaddr = sym->value + sym->section->vma;
              break;
            }
@@ -331,7 +340,7 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
   If FROM_TTYP dereferences to a non-zero integer, allow messages to
   be printed.  This parameter is a pointer rather than an int because
   open_symbol_file_object() is called via catch_errors() and
-  catch_errors() requires a pointer argument. */
+  catch_errors() requires a pointer argument.  */
 
 static int
 open_symbol_file_object (void *from_ttyp)
@@ -357,10 +366,19 @@ static CORE_ADDR main_lm_addr = 0;
 static CORE_ADDR
 lm_base (void)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
   struct minimal_symbol *got_sym;
   CORE_ADDR addr;
   gdb_byte buf[FRV_PTR_SIZE];
 
+  /* One of our assumptions is that the main executable has been relocated.
+     Bail out if this has not happened.  (Note that post_create_inferior()
+     in infcmd.c will call solib_add prior to solib_create_inferior_hook().
+     If we allow this to happen, lm_base_cache will be initialized with
+     a bogus value.  */
+  if (main_executable_lm_info == 0)
+    return 0;
+
   /* If we already have a cached value, return it.  */
   if (lm_base_cache)
     return lm_base_cache;
@@ -384,7 +402,7 @@ lm_base (void)
 
   if (target_read_memory (addr, buf, sizeof buf) != 0)
     return 0;
-  lm_base_cache = extract_unsigned_integer (buf, sizeof buf);
+  lm_base_cache = extract_unsigned_integer (buf, sizeof buf, byte_order);
 
   if (solib_frv_debug)
     fprintf_unfiltered (gdb_stdlog,
@@ -417,6 +435,7 @@ lm_base (void)
 static struct so_list *
 frv_current_sos (void)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
   CORE_ADDR lm_addr, mgot;
   struct so_list *sos_head = NULL;
   struct so_list **sos_next_ptr = &sos_head;
@@ -454,15 +473,18 @@ frv_current_sos (void)
                            "current_sos: reading link_map entry at %s\n",
                            hex_string_custom (lm_addr, 8));
 
-      if (target_read_memory (lm_addr, (gdb_byte *) &lm_buf, sizeof (lm_buf)) != 0)
+      if (target_read_memory (lm_addr, (gdb_byte *) &lm_buf,
+                             sizeof (lm_buf)) != 0)
        {
-         warning (_("frv_current_sos: Unable to read link map entry.  Shared object chain may be incomplete."));
+         warning (_("frv_current_sos: Unable to read link map entry.  "
+                    "Shared object chain may be incomplete."));
          break;
        }
 
       got_addr
        = extract_unsigned_integer (lm_buf.l_addr.got_value,
-                                   sizeof (lm_buf.l_addr.got_value));
+                                   sizeof (lm_buf.l_addr.got_value),
+                                   byte_order);
       /* If the got_addr is the same as mgotr, then we're looking at the
         entry for the main executable.  By convention, we don't include
         this in the list of shared objects.  */
@@ -476,11 +498,13 @@ frv_current_sos (void)
 
          /* Fetch the load map address.  */
          addr = extract_unsigned_integer (lm_buf.l_addr.map,
-                                          sizeof lm_buf.l_addr.map);
+                                          sizeof lm_buf.l_addr.map,
+                                          byte_order);
          loadmap = fetch_loadmap (addr);
          if (loadmap == NULL)
            {
-             warning (_("frv_current_sos: Unable to fetch load map.  Shared object chain may be incomplete."));
+             warning (_("frv_current_sos: Unable to fetch load map.  "
+                        "Shared object chain may be incomplete."));
              break;
            }
 
@@ -491,7 +515,8 @@ frv_current_sos (void)
          sop->lm_info->lm_addr = lm_addr;
          /* Fetch the name.  */
          addr = extract_unsigned_integer (lm_buf.l_name,
-                                          sizeof (lm_buf.l_name));
+                                          sizeof (lm_buf.l_name),
+                                          byte_order);
          target_read_string (addr, &name_buf, SO_NAME_MAX_PATH_SIZE - 1,
                              &errcode);
 
@@ -518,7 +543,8 @@ frv_current_sos (void)
          main_lm_addr = lm_addr;
        }
 
-      lm_addr = extract_unsigned_integer (lm_buf.l_next, sizeof (lm_buf.l_next));
+      lm_addr = extract_unsigned_integer (lm_buf.l_next,
+                                         sizeof (lm_buf.l_next), byte_order);
     }
 
   enable_break2 ();
@@ -546,7 +572,7 @@ frv_in_dynsym_resolve_code (CORE_ADDR pc)
 /* Given a loadmap and an address, return the displacement needed
    to relocate the address.  */
 
-CORE_ADDR
+static CORE_ADDR
 displacement_from_map (struct int_elf32_fdpic_loadmap *map,
                        CORE_ADDR addr)
 {
@@ -609,25 +635,19 @@ enable_break_failure_warning (void)
 
  */
 
-static int enable_break1_done = 0;
 static int enable_break2_done = 0;
 
 static int
 enable_break2 (void)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
   int success = 0;
   char **bkpt_namep;
   asection *interp_sect;
 
-  if (!enable_break1_done || enable_break2_done)
+  if (enable_break2_done)
     return 1;
 
-  enable_break2_done = 1;
-
-  /* First, remove all the solib event breakpoints.  Their addresses
-     may have changed since the last time we ran the program.  */
-  remove_solib_event_breakpoints ();
-
   interp_text_sect_low = interp_text_sect_high = 0;
   interp_plt_sect_low = interp_plt_sect_high = 0;
 
@@ -639,12 +659,11 @@ enable_break2 (void)
       unsigned int interp_sect_size;
       gdb_byte *buf;
       bfd *tmp_bfd = NULL;
-      int tmp_fd = -1;
-      char *tmp_pathname = NULL;
       int status;
       CORE_ADDR addr, interp_loadmap_addr;
       gdb_byte addr_buf[FRV_PTR_SIZE];
       struct int_elf32_fdpic_loadmap *ldm;
+      volatile struct gdb_exception ex;
 
       /* Read the contents of the .interp section into a local buffer;
          the contents specify the dynamic linker this program uses.  */
@@ -662,26 +681,17 @@ enable_break2 (void)
          be trivial on GNU/Linux).  Therefore, we have to try an alternate
          mechanism to find the dynamic linker's base address.  */
 
-      tmp_fd  = solib_open (buf, &tmp_pathname);
-      if (tmp_fd >= 0)
-       tmp_bfd = bfd_fopen (tmp_pathname, gnutarget, FOPEN_RB, tmp_fd);
-
+      TRY_CATCH (ex, RETURN_MASK_ALL)
+        {
+          tmp_bfd = solib_bfd_open (buf);
+        }
       if (tmp_bfd == NULL)
        {
          enable_break_failure_warning ();
          return 0;
        }
 
-      /* Make sure the dynamic linker is really a useful object.  */
-      if (!bfd_check_format (tmp_bfd, bfd_object))
-       {
-         warning (_("Unable to grok dynamic linker %s as an object file"), buf);
-         enable_break_failure_warning ();
-         bfd_close (tmp_bfd);
-         return 0;
-       }
-
-      status = frv_fdpic_loadmap_addresses (current_gdbarch,
+      status = frv_fdpic_loadmap_addresses (target_gdbarch,
                                             &interp_loadmap_addr, 0);
       if (status < 0)
        {
@@ -732,7 +742,8 @@ enable_break2 (void)
       addr = bfd_lookup_symbol (tmp_bfd, "_dl_debug_addr");
       if (addr == 0)
        {
-         warning (_("Could not find symbol _dl_debug_addr in dynamic linker"));
+         warning (_("Could not find symbol _dl_debug_addr "
+                    "in dynamic linker"));
          enable_break_failure_warning ();
          bfd_close (tmp_bfd);
          return 0;
@@ -740,46 +751,67 @@ enable_break2 (void)
 
       if (solib_frv_debug)
        fprintf_unfiltered (gdb_stdlog,
-                           "enable_break: _dl_debug_addr (prior to relocation) = %s\n",
+                           "enable_break: _dl_debug_addr "
+                           "(prior to relocation) = %s\n",
                            hex_string_custom (addr, 8));
 
       addr += displacement_from_map (ldm, addr);
 
       if (solib_frv_debug)
        fprintf_unfiltered (gdb_stdlog,
-                           "enable_break: _dl_debug_addr (after relocation) = %s\n",
+                           "enable_break: _dl_debug_addr "
+                           "(after relocation) = %s\n",
                            hex_string_custom (addr, 8));
 
       /* Fetch the address of the r_debug struct.  */
       if (target_read_memory (addr, addr_buf, sizeof addr_buf) != 0)
        {
-         warning (_("Unable to fetch contents of _dl_debug_addr (at address %s) from dynamic linker"),
+         warning (_("Unable to fetch contents of _dl_debug_addr "
+                    "(at address %s) from dynamic linker"),
                   hex_string_custom (addr, 8));
        }
-      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf, byte_order);
+
+      if (solib_frv_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "enable_break: _dl_debug_addr[0..3] = %s\n",
+                           hex_string_custom (addr, 8));
+
+      /* If it's zero, then the ldso hasn't initialized yet, and so
+         there are no shared libs yet loaded.  */
+      if (addr == 0)
+       {
+         if (solib_frv_debug)
+           fprintf_unfiltered (gdb_stdlog,
+                               "enable_break: ldso not yet initialized\n");
+         /* Do not warn, but mark to run again.  */
+         return 0;
+       }
 
       /* Fetch the r_brk field.  It's 8 bytes from the start of
          _dl_debug_addr.  */
       if (target_read_memory (addr + 8, addr_buf, sizeof addr_buf) != 0)
        {
-         warning (_("Unable to fetch _dl_debug_addr->r_brk (at address %s) from dynamic linker"),
+         warning (_("Unable to fetch _dl_debug_addr->r_brk "
+                    "(at address %s) from dynamic linker"),
                   hex_string_custom (addr + 8, 8));
          enable_break_failure_warning ();
          bfd_close (tmp_bfd);
          return 0;
        }
-      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf, byte_order);
 
       /* Now fetch the function entry point.  */
       if (target_read_memory (addr, addr_buf, sizeof addr_buf) != 0)
        {
-         warning (_("Unable to fetch _dl_debug_addr->.r_brk entry point (at address %s) from dynamic linker"),
+         warning (_("Unable to fetch _dl_debug_addr->.r_brk entry point "
+                    "(at address %s) from dynamic linker"),
                   hex_string_custom (addr, 8));
          enable_break_failure_warning ();
          bfd_close (tmp_bfd);
          return 0;
        }
-      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf, byte_order);
 
       /* We're done with the temporary bfd.  */
       bfd_close (tmp_bfd);
@@ -787,8 +819,14 @@ enable_break2 (void)
       /* We're also done with the loadmap.  */
       xfree (ldm);
 
+      /* Remove all the solib event breakpoints.  Their addresses
+         may have changed since the last time we ran the program.  */
+      remove_solib_event_breakpoints ();
+
       /* Now (finally!) create the solib breakpoint.  */
-      create_solib_event_breakpoint (addr);
+      create_solib_event_breakpoint (target_gdbarch, addr);
+
+      enable_break2_done = 1;
 
       return 1;
     }
@@ -805,33 +843,44 @@ enable_break (void)
 {
   asection *interp_sect;
 
-  /* Remove all the solib event breakpoints.  Their addresses
-     may have changed since the last time we ran the program.  */
-  remove_solib_event_breakpoints ();
+  if (symfile_objfile == NULL)
+    {
+      if (solib_frv_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "enable_break: No symbol file found.\n");
+      return 0;
+    }
+
+  if (!symfile_objfile->ei.entry_point_p)
+    {
+      if (solib_frv_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "enable_break: Symbol file has no entry point.\n");
+      return 0;
+    }
 
   /* Check for the presence of a .interp section.  If there is no
      such section, the executable is statically linked.  */
 
   interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
 
-  if (interp_sect)
+  if (interp_sect == NULL)
     {
-      enable_break1_done = 1;
-      create_solib_event_breakpoint (symfile_objfile->ei.entry_point);
-
       if (solib_frv_debug)
        fprintf_unfiltered (gdb_stdlog,
-                           "enable_break: solib event breakpoint placed at entry point: %s\n",
-                           hex_string_custom
-                             (symfile_objfile->ei.entry_point, 8));
-    }
-  else
-    {
-      if (solib_frv_debug)
-       fprintf_unfiltered (gdb_stdlog,
-                           "enable_break: No .interp section found.\n");
+                           "enable_break: No .interp section found.\n");
+      return 0;
     }
 
+  create_solib_event_breakpoint (target_gdbarch,
+                                symfile_objfile->ei.entry_point);
+
+  if (solib_frv_debug)
+    fprintf_unfiltered (gdb_stdlog,
+                       "enable_break: solib event breakpoint "
+                       "placed at entry point: %s\n",
+                       hex_string_custom (symfile_objfile->ei.entry_point,
+                                          8));
   return 1;
 }
 
@@ -856,23 +905,24 @@ enable_break (void)
 static void
 frv_special_symbol_handling (void)
 {
-  /* Nothing needed (yet) for FRV. */
+  /* Nothing needed (yet) for FRV.  */
 }
 
 static void
 frv_relocate_main_executable (void)
 {
   int status;
-  CORE_ADDR exec_addr;
+  CORE_ADDR exec_addr, interp_addr;
   struct int_elf32_fdpic_loadmap *ldm;
   struct cleanup *old_chain;
   struct section_offsets *new_offsets;
   int changed;
   struct obj_section *osect;
 
-  status = frv_fdpic_loadmap_addresses (current_gdbarch, 0, &exec_addr);
+  status = frv_fdpic_loadmap_addresses (target_gdbarch,
+                                        &interp_addr, &exec_addr);
 
-  if (status < 0)
+  if (status < 0 || (exec_addr == 0 && interp_addr == 0))
     {
       /* Not using FDPIC ABI, so do nothing.  */
       return;
@@ -902,7 +952,7 @@ frv_relocate_main_executable (void)
       osect_idx = osect->the_bfd_section->index;
 
       /* Current address of section.  */
-      addr = osect->addr;
+      addr = obj_section_addr (osect);
       /* Offset from where this section started.  */
       offset = ANOFFSET (symfile_objfile->section_offsets, osect_idx);
       /* Original address prior to any past relocations.  */
@@ -956,7 +1006,7 @@ frv_relocate_main_executable (void)
  */
 
 static void
-frv_solib_create_inferior_hook (void)
+frv_solib_create_inferior_hook (int from_tty)
 {
   /* Relocate main executable.  */
   frv_relocate_main_executable ();
@@ -973,7 +1023,6 @@ static void
 frv_clear_solib (void)
 {
   lm_base_cache = 0;
-  enable_break1_done = 0;
   enable_break2_done = 0;
   main_lm_addr = 0;
   if (main_executable_lm_info != 0)
@@ -997,7 +1046,7 @@ frv_free_so (struct so_list *so)
 
 static void
 frv_relocate_section_addresses (struct so_list *so,
-                                 struct section_table *sec)
+                                 struct target_section *sec)
 {
   int seg;
   struct int_elf32_fdpic_loadmap *map;
@@ -1010,6 +1059,7 @@ frv_relocate_section_addresses (struct so_list *so,
           && sec->addr < map->segs[seg].p_vaddr + map->segs[seg].p_memsz)
        {
          CORE_ADDR displ = map->segs[seg].addr - map->segs[seg].p_vaddr;
+
          sec->addr += displ;
          sec->endaddr += displ;
          break;
@@ -1025,7 +1075,8 @@ main_got (void)
 {
   struct minimal_symbol *got_sym;
 
-  got_sym = lookup_minimal_symbol ("_GLOBAL_OFFSET_TABLE_", NULL, symfile_objfile);
+  got_sym = lookup_minimal_symbol ("_GLOBAL_OFFSET_TABLE_",
+                                  NULL, symfile_objfile);
   if (got_sym == 0)
     return 0;
 
@@ -1125,6 +1176,7 @@ find_canonical_descriptor_in_load_object
   (CORE_ADDR entry_point, CORE_ADDR got_value, char *name, bfd *abfd,
    struct lm_info *lm)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
   arelent *rel;
   unsigned int i;
   CORE_ADDR addr = 0;
@@ -1217,18 +1269,20 @@ find_canonical_descriptor_in_load_object
          /* Fetch address of candidate descriptor.  */
          if (target_read_memory (addr, buf, sizeof buf) != 0)
            continue;
-         addr = extract_unsigned_integer (buf, sizeof buf);
+         addr = extract_unsigned_integer (buf, sizeof buf, byte_order);
 
          /* Check for matching entry point.  */
          if (target_read_memory (addr, buf, sizeof buf) != 0)
            continue;
-         if (extract_unsigned_integer (buf, sizeof buf) != entry_point)
+         if (extract_unsigned_integer (buf, sizeof buf, byte_order)
+             != entry_point)
            continue;
 
          /* Check for matching got value.  */
          if (target_read_memory (addr + 4, buf, sizeof buf) != 0)
            continue;
-         if (extract_unsigned_integer (buf, sizeof buf) != got_value)
+         if (extract_unsigned_integer (buf, sizeof buf, byte_order)
+             != got_value)
            continue;
 
          /* Match was successful!  Exit loop.  */
@@ -1266,7 +1320,10 @@ frv_fetch_objfile_link_map (struct objfile *objfile)
   return 0;
 }
 
-static struct target_so_ops frv_so_ops;
+struct target_so_ops frv_so_ops;
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_frv_solib;
 
 void
 _initialize_frv_solib (void)
@@ -1279,9 +1336,7 @@ _initialize_frv_solib (void)
   frv_so_ops.current_sos = frv_current_sos;
   frv_so_ops.open_symbol_file_object = open_symbol_file_object;
   frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code;
-
-  /* FIXME: Don't do this here.  *_gdbarch_init() should set so_ops. */
-  current_target_so_ops = &frv_so_ops;
+  frv_so_ops.bfd_open = solib_bfd_open;
 
   /* Debug this file's internals.  */
   add_setshow_zinteger_cmd ("solib-frv", class_maintenance,
This page took 0.045149 seconds and 4 git commands to generate.