]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
This commit was manufactured by cvs2svn to create branch
authornobody <>
Wed, 30 Apr 2003 01:27:54 +0000 (01:27 +0000)
committernobody <>
Wed, 30 Apr 2003 01:27:54 +0000 (01:27 +0000)
'carlton_dictionary-branch'.

Cherrypick from master 2003-04-30 01:27:53 UTC Adam Fedor <fedor@gnu.org> '* eval.c (evaluate_subexp_standard): Handle ObjC ops.':
    bfd/elf32-m68hc1x.c
    bfd/elf32-m68hc1x.h
    gdb/gdb_gcore.sh
    gdb/infcall.c
    gdb/infcall.h
    libiberty/snprintf.c
    libiberty/vsnprintf.c

bfd/elf32-m68hc1x.c [new file with mode: 0644]
bfd/elf32-m68hc1x.h [new file with mode: 0644]
gdb/gdb_gcore.sh [new file with mode: 0755]
gdb/infcall.c [new file with mode: 0644]
gdb/infcall.h [new file with mode: 0644]
libiberty/snprintf.c [new file with mode: 0644]
libiberty/vsnprintf.c [new file with mode: 0644]

diff --git a/bfd/elf32-m68hc1x.c b/bfd/elf32-m68hc1x.c
new file mode 100644 (file)
index 0000000..0696a36
--- /dev/null
@@ -0,0 +1,1508 @@
+/* Motorola 68HC11/HC12-specific support for 32-bit ELF
+   Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Contributed by Stephane Carrez (stcarrez@nerim.fr)
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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
+(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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "elf32-m68hc1x.h"
+#include "elf/m68hc11.h"
+#include "opcode/m68hc11.h"
+
+
+#define m68hc12_stub_hash_lookup(table, string, create, copy) \
+  ((struct elf32_m68hc11_stub_hash_entry *) \
+   bfd_hash_lookup ((table), (string), (create), (copy)))
+
+static struct elf32_m68hc11_stub_hash_entry* m68hc12_add_stub
+  PARAMS((const char *stub_name,
+          asection *section,
+          struct m68hc11_elf_link_hash_table *htab));
+
+static struct bfd_hash_entry *stub_hash_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+
+static void m68hc11_elf_set_symbol
+  PARAMS ((bfd* abfd, struct bfd_link_info *info,
+           const char* name, bfd_vma value, asection* sec));
+
+static bfd_boolean m68hc11_elf_export_one_stub
+  PARAMS((struct bfd_hash_entry *gen_entry, PTR in_arg));
+
+static bfd_boolean m68hc11_get_relocation_value
+  PARAMS ((bfd* abfd,
+           struct bfd_link_info* info,
+           asection **local_sections,
+           Elf_Internal_Sym* local_syms,
+           Elf_Internal_Rela* rel,
+           const char** name,
+           bfd_vma* relocation,
+           bfd_boolean* is_far));
+
+static void scan_sections_for_abi PARAMS ((bfd*, asection*, PTR));
+
+struct m68hc11_scan_param
+{
+   struct m68hc11_page_info* pinfo;
+   bfd_boolean use_memory_banks;
+};
+
+
+/* Create a 68HC11/68HC12 ELF linker hash table.  */
+
+struct m68hc11_elf_link_hash_table*
+m68hc11_elf_hash_table_create (abfd)
+     bfd *abfd;
+{
+  struct m68hc11_elf_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct m68hc11_elf_link_hash_table);
+
+  ret = (struct m68hc11_elf_link_hash_table *) bfd_zalloc (abfd, amt);
+  if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
+    return NULL;
+
+  if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
+                                      _bfd_elf_link_hash_newfunc))
+    {
+      bfd_release (abfd, ret);
+      return NULL;
+    }
+
+  /* Init the stub hash table too.  */
+  amt = sizeof (struct bfd_hash_table);
+  ret->stub_hash_table = (struct bfd_hash_table*) bfd_malloc (amt);
+  if (ret->stub_hash_table == NULL)
+    {
+      bfd_release (abfd, ret);
+      return NULL;
+    }
+  if (!bfd_hash_table_init (ret->stub_hash_table, stub_hash_newfunc))
+    return NULL;
+
+  ret->stub_bfd = NULL;
+  ret->stub_section = 0;
+  ret->add_stub_section = NULL;
+  ret->sym_sec.abfd = NULL;
+
+  return ret;
+}
+
+/* Free the derived linker hash table.  */
+
+void
+m68hc11_elf_bfd_link_hash_table_free (hash)
+     struct bfd_link_hash_table *hash;
+{
+  struct m68hc11_elf_link_hash_table *ret
+    = (struct m68hc11_elf_link_hash_table *) hash;
+
+  bfd_hash_table_free (ret->stub_hash_table);
+  free (ret->stub_hash_table);
+  _bfd_generic_link_hash_table_free (hash);
+}
+
+/* Assorted hash table functions.  */
+
+/* Initialize an entry in the stub hash table.  */
+
+static struct bfd_hash_entry *
+stub_hash_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table,
+                                sizeof (struct elf32_m68hc11_stub_hash_entry));
+      if (entry == NULL)
+       return entry;
+    }
+
+  /* Call the allocation method of the superclass.  */
+  entry = bfd_hash_newfunc (entry, table, string);
+  if (entry != NULL)
+    {
+      struct elf32_m68hc11_stub_hash_entry *eh;
+
+      /* Initialize the local fields.  */
+      eh = (struct elf32_m68hc11_stub_hash_entry *) entry;
+      eh->stub_sec = NULL;
+      eh->stub_offset = 0;
+      eh->target_value = 0;
+      eh->target_section = NULL;
+    }
+
+  return entry;
+}
+
+/* Add a new stub entry to the stub hash.  Not all fields of the new
+   stub entry are initialised.  */
+
+static struct elf32_m68hc11_stub_hash_entry *
+m68hc12_add_stub (stub_name, section, htab)
+     const char *stub_name;
+     asection *section;
+     struct m68hc11_elf_link_hash_table *htab;
+{
+  struct elf32_m68hc11_stub_hash_entry *stub_entry;
+
+  /* Enter this entry into the linker stub hash table.  */
+  stub_entry = m68hc12_stub_hash_lookup (htab->stub_hash_table, stub_name,
+                                         TRUE, FALSE);
+  if (stub_entry == NULL)
+    {
+      (*_bfd_error_handler) (_("%s: cannot create stub entry %s"),
+                            bfd_archive_filename (section->owner),
+                            stub_name);
+      return NULL;
+    }
+
+  if (htab->stub_section == 0)
+    {
+      htab->stub_section = (*htab->add_stub_section) (".tramp",
+                                                      htab->tramp_section);
+    }
+
+  stub_entry->stub_sec = htab->stub_section;
+  stub_entry->stub_offset = 0;
+  return stub_entry;
+}
+
+/* Hook called by the linker routine which adds symbols from an object
+   file.  We use it for identify far symbols and force a loading of
+   the trampoline handler.  */
+
+bfd_boolean
+elf32_m68hc11_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     const Elf_Internal_Sym *sym;
+     const char **namep ATTRIBUTE_UNUSED;
+     flagword *flagsp ATTRIBUTE_UNUSED;
+     asection **secp ATTRIBUTE_UNUSED;
+     bfd_vma *valp ATTRIBUTE_UNUSED;
+{
+  if (sym->st_other & STO_M68HC12_FAR)
+    {
+      struct elf_link_hash_entry *h;
+
+      h = (struct elf_link_hash_entry *)
+       bfd_link_hash_lookup (info->hash, "__far_trampoline",
+                              FALSE, FALSE, FALSE);
+      if (h == NULL)
+        {
+          struct bfd_link_hash_entry* entry = NULL;
+
+          _bfd_generic_link_add_one_symbol (info, abfd,
+                                            "__far_trampoline",
+                                            BSF_GLOBAL,
+                                            bfd_und_section_ptr,
+                                            (bfd_vma) 0, (const char*) NULL,
+                                            FALSE, FALSE, &entry);
+        }
+
+    }
+  return TRUE;
+}
+
+/* External entry points for sizing and building linker stubs.  */
+
+/* Set up various things so that we can make a list of input sections
+   for each output section included in the link.  Returns -1 on error,
+   0 when no stubs will be needed, and 1 on success.  */
+
+int
+elf32_m68hc11_setup_section_lists (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  bfd *input_bfd;
+  unsigned int bfd_count;
+  int top_id, top_index;
+  asection *section;
+  asection **input_list, **list;
+  bfd_size_type amt;
+  asection *text_section;
+  struct m68hc11_elf_link_hash_table *htab;
+
+  htab = m68hc11_elf_hash_table (info);
+
+  if (htab->root.root.creator->flavour != bfd_target_elf_flavour)
+    return 0;
+
+  /* Count the number of input BFDs and find the top input section id.
+     Also search for an existing ".tramp" section so that we know
+     where generated trampolines must go.  Default to ".text" if we
+     can't find it.  */
+  htab->tramp_section = 0;
+  text_section = 0;
+  for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next)
+    {
+      bfd_count += 1;
+      for (section = input_bfd->sections;
+          section != NULL;
+          section = section->next)
+       {
+          const char* name = bfd_get_section_name (input_bfd, section);
+
+          if (!strcmp (name, ".tramp"))
+            htab->tramp_section = section;
+
+          if (!strcmp (name, ".text"))
+            text_section = section;
+
+         if (top_id < section->id)
+           top_id = section->id;
+       }
+    }
+  htab->bfd_count = bfd_count;
+  if (htab->tramp_section == 0)
+    htab->tramp_section = text_section;
+
+  /* We can't use output_bfd->section_count here to find the top output
+     section index as some sections may have been removed, and
+     _bfd_strip_section_from_output doesn't renumber the indices.  */
+  for (section = output_bfd->sections, top_index = 0;
+       section != NULL;
+       section = section->next)
+    {
+      if (top_index < section->index)
+       top_index = section->index;
+    }
+
+  htab->top_index = top_index;
+  amt = sizeof (asection *) * (top_index + 1);
+  input_list = (asection **) bfd_malloc (amt);
+  htab->input_list = input_list;
+  if (input_list == NULL)
+    return -1;
+
+  /* For sections we aren't interested in, mark their entries with a
+     value we can check later.  */
+  list = input_list + top_index;
+  do
+    *list = bfd_abs_section_ptr;
+  while (list-- != input_list);
+
+  for (section = output_bfd->sections;
+       section != NULL;
+       section = section->next)
+    {
+      if ((section->flags & SEC_CODE) != 0)
+       input_list[section->index] = NULL;
+    }
+
+  return 1;
+}
+
+/* Determine and set the size of the stub section for a final link.
+
+   The basic idea here is to examine all the relocations looking for
+   PC-relative calls to a target that is unreachable with a "bl"
+   instruction.  */
+
+bfd_boolean
+elf32_m68hc11_size_stubs (output_bfd, stub_bfd, info, add_stub_section)
+     bfd *output_bfd;
+     bfd *stub_bfd;
+     struct bfd_link_info *info;
+     asection * (*add_stub_section) PARAMS ((const char *, asection *));
+{
+  bfd *input_bfd;
+  asection *section;
+  Elf_Internal_Sym *local_syms, **all_local_syms;
+  unsigned int bfd_indx, bfd_count;
+  bfd_size_type amt;
+  asection *stub_sec;
+
+  struct m68hc11_elf_link_hash_table *htab = m68hc11_elf_hash_table (info);
+
+  /* Stash our params away.  */
+  htab->stub_bfd = stub_bfd;
+  htab->add_stub_section = add_stub_section;
+
+  /* Count the number of input BFDs and find the top input section id.  */
+  for (input_bfd = info->input_bfds, bfd_count = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next)
+    {
+      bfd_count += 1;
+    }
+
+  /* We want to read in symbol extension records only once.  To do this
+     we need to read in the local symbols in parallel and save them for
+     later use; so hold pointers to the local symbols in an array.  */
+  amt = sizeof (Elf_Internal_Sym *) * bfd_count;
+  all_local_syms = (Elf_Internal_Sym **) bfd_zmalloc (amt);
+  if (all_local_syms == NULL)
+    return FALSE;
+
+  /* Walk over all the input BFDs, swapping in local symbols.  */
+  for (input_bfd = info->input_bfds, bfd_indx = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next, bfd_indx++)
+    {
+      Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Shdr *shndx_hdr;
+      Elf_Internal_Sym *isym;
+      Elf32_External_Sym *extsyms, *esym, *end_sy;
+      Elf_External_Sym_Shndx *shndx_buf, *shndx;
+      bfd_size_type sec_size;
+
+      /* We'll need the symbol table in a second.  */
+      symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+      if (symtab_hdr->sh_info == 0)
+       continue;
+
+      /* We need an array of the local symbols attached to the input bfd.
+        Unfortunately, we're going to have to read & swap them in.  */
+      sec_size = symtab_hdr->sh_info;
+      sec_size *= sizeof (Elf_Internal_Sym);
+      local_syms = (Elf_Internal_Sym *) bfd_malloc (sec_size);
+      if (local_syms == NULL)
+       goto error_ret_free_local;
+
+      all_local_syms[bfd_indx] = local_syms;
+      sec_size = symtab_hdr->sh_info;
+      sec_size *= sizeof (Elf32_External_Sym);
+
+      /* Get the cached copy.  */
+      if (symtab_hdr->contents != NULL)
+        extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
+      else
+        {
+          /* Go get them off disk.  */
+          bfd_size_type amt = symtab_hdr->sh_size;
+          extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
+          if (extsyms == NULL)
+            goto error_ret_free_local;
+
+          if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+              || bfd_bread ((PTR) extsyms, amt, input_bfd) != amt)
+            {
+            error_ret_free_ext_syms:
+              free (extsyms);
+              goto error_ret_free_local;
+            }
+        }
+      shndx_buf = NULL;
+      shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
+      if (shndx_hdr->sh_size != 0)
+        {
+          bfd_size_type amt;
+
+          amt = symtab_hdr->sh_info * sizeof (Elf_External_Sym_Shndx);
+          shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+          if (shndx_buf == NULL)
+            goto error_ret_free_ext_syms;
+          if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+              || bfd_bread ((PTR) shndx_buf, amt, input_bfd) != amt)
+            {
+              free (shndx_buf);
+              goto error_ret_free_ext_syms;
+            }
+          shndx_hdr->contents = (PTR) shndx_buf;
+        }
+
+      /* Swap the local symbols in.  */
+      for (esym = extsyms, end_sy = esym + symtab_hdr->sh_info,
+            isym = local_syms, shndx = shndx_buf;
+          esym < end_sy;
+          esym++, isym++, shndx = (shndx ? shndx + 1 : NULL))
+       bfd_elf32_swap_symbol_in (input_bfd, esym, shndx, isym);
+
+      /* Now we can free the external symbols.  */
+      free (shndx_buf);
+    }
+
+  for (input_bfd = info->input_bfds, bfd_indx = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next, bfd_indx++)
+    {
+      Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Sym *local_syms;
+      struct elf_link_hash_entry ** sym_hashes;
+
+      sym_hashes = elf_sym_hashes (input_bfd);
+
+      /* We'll need the symbol table in a second.  */
+      symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+      if (symtab_hdr->sh_info == 0)
+        continue;
+
+      local_syms = all_local_syms[bfd_indx];
+
+      /* Walk over each section attached to the input bfd.  */
+      for (section = input_bfd->sections;
+           section != NULL;
+           section = section->next)
+        {
+          Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
+
+          /* If there aren't any relocs, then there's nothing more
+             to do.  */
+          if ((section->flags & SEC_RELOC) == 0
+              || section->reloc_count == 0)
+            continue;
+
+          /* If this section is a link-once section that will be
+             discarded, then don't create any stubs.  */
+          if (section->output_section == NULL
+              || section->output_section->owner != output_bfd)
+            continue;
+
+          /* Get the relocs.  */
+          internal_relocs
+            = _bfd_elf32_link_read_relocs (input_bfd, section, NULL,
+                                           (Elf_Internal_Rela *) NULL,
+                                           info->keep_memory);
+          if (internal_relocs == NULL)
+            goto error_ret_free_local;
+
+          /* Now examine each relocation.  */
+          irela = internal_relocs;
+          irelaend = irela + section->reloc_count;
+          for (; irela < irelaend; irela++)
+            {
+              unsigned int r_type, r_indx;
+              struct elf32_m68hc11_stub_hash_entry *stub_entry;
+              asection *sym_sec;
+              bfd_vma sym_value;
+              struct elf_link_hash_entry *hash;
+              const char *stub_name;
+              Elf_Internal_Sym *sym;
+
+              r_type = ELF32_R_TYPE (irela->r_info);
+
+              /* Only look at 16-bit relocs.  */
+              if (r_type != (unsigned int) R_M68HC11_16)
+                continue;
+
+              /* Now determine the call target, its name, value,
+                 section.  */
+              r_indx = ELF32_R_SYM (irela->r_info);
+              if (r_indx < symtab_hdr->sh_info)
+                {
+                  /* It's a local symbol.  */
+                  Elf_Internal_Shdr *hdr;
+                  bfd_boolean is_far;
+
+                  sym = local_syms + r_indx;
+                  hdr = elf_elfsections (input_bfd)[sym->st_shndx];
+                  sym_sec = hdr->bfd_section;
+                  is_far = (sym && (sym->st_other & STO_M68HC12_FAR));
+                  if (!is_far)
+                    continue;
+                  stub_name = (bfd_elf_string_from_elf_section
+                               (input_bfd, symtab_hdr->sh_link,
+                                sym->st_name));
+                  sym_value = sym->st_value;
+                  hash = NULL;
+                }
+              else
+                {
+                  /* It's an external symbol.  */
+                  int e_indx;
+
+                  e_indx = r_indx - symtab_hdr->sh_info;
+                  hash = (struct elf_link_hash_entry *)
+                    (sym_hashes[e_indx]);
+
+                  while (hash->root.type == bfd_link_hash_indirect
+                         || hash->root.type == bfd_link_hash_warning)
+                    hash = ((struct elf_link_hash_entry *)
+                            hash->root.u.i.link);
+
+                  if (hash->root.type == bfd_link_hash_defined
+                      || hash->root.type == bfd_link_hash_defweak)
+                    {
+                      if (!(hash->other & STO_M68HC12_FAR))
+                        continue;
+                    }
+                  else if (hash->root.type == bfd_link_hash_undefweak)
+                    {
+                      continue;
+                    }
+                  else if (hash->root.type == bfd_link_hash_undefined)
+                    {
+                      continue;
+                    }
+                  else
+                    {
+                      bfd_set_error (bfd_error_bad_value);
+                      goto error_ret_free_internal;
+                    }
+                  sym_sec = hash->root.u.def.section;
+                  sym_value = hash->root.u.def.value;
+                  stub_name = hash->root.root.string;
+                }
+
+              if (!stub_name)
+                goto error_ret_free_internal;
+
+              stub_entry = m68hc12_stub_hash_lookup
+                (htab->stub_hash_table,
+                 stub_name,
+                 FALSE, FALSE);
+              if (stub_entry == NULL)
+                {
+                  if (add_stub_section == 0)
+                    continue;
+
+                  stub_entry = m68hc12_add_stub (stub_name, section, htab);
+                  if (stub_entry == NULL)
+                    {
+                    error_ret_free_internal:
+                      if (elf_section_data (section)->relocs == NULL)
+                        free (internal_relocs);
+                      goto error_ret_free_local;
+                    }
+                }
+
+              stub_entry->target_value = sym_value;
+              stub_entry->target_section = sym_sec;
+            }
+
+          /* We're done with the internal relocs, free them.  */
+          if (elf_section_data (section)->relocs == NULL)
+            free (internal_relocs);
+        }
+    }
+
+  if (add_stub_section)
+    {
+      /* OK, we've added some stubs.  Find out the new size of the
+         stub sections.  */
+      for (stub_sec = htab->stub_bfd->sections;
+           stub_sec != NULL;
+           stub_sec = stub_sec->next)
+        {
+          stub_sec->_raw_size = 0;
+          stub_sec->_cooked_size = 0;
+        }
+
+      bfd_hash_traverse (htab->stub_hash_table, htab->size_one_stub, htab);
+    }
+  free (htab->all_local_syms);
+  return TRUE;
+
+ error_ret_free_local:
+  free (htab->all_local_syms);
+  return FALSE;
+}
+
+/* Export the trampoline addresses in the symbol table.  */
+static bfd_boolean
+m68hc11_elf_export_one_stub (gen_entry, in_arg)
+     struct bfd_hash_entry *gen_entry;
+     PTR in_arg;
+{
+  struct bfd_link_info *info;
+  struct m68hc11_elf_link_hash_table *htab;
+  struct elf32_m68hc11_stub_hash_entry *stub_entry;
+  char* name;
+  bfd_boolean result;
+
+  info = (struct bfd_link_info *) in_arg;
+  htab = m68hc11_elf_hash_table (info);
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
+
+  /* Generate the trampoline according to HC11 or HC12.  */
+  result = (* htab->build_one_stub) (gen_entry, in_arg);
+
+  /* Make a printable name that does not conflict with the real function.  */
+  name = alloca (strlen (stub_entry->root.string) + 16);
+  sprintf (name, "tramp.%s", stub_entry->root.string);
+
+  /* Export the symbol for debugging/disassembling.  */
+  m68hc11_elf_set_symbol (htab->stub_bfd, info, name,
+                          stub_entry->stub_offset,
+                          stub_entry->stub_sec);
+  return result;
+}
+
+/* Export a symbol or set its value and section.  */
+static void
+m68hc11_elf_set_symbol (abfd, info, name, value, sec)
+     bfd* abfd;
+     struct bfd_link_info *info;
+     const char* name;
+     bfd_vma value;
+     asection* sec;
+{
+  struct elf_link_hash_entry *h;
+
+  h = (struct elf_link_hash_entry *)
+    bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, FALSE);
+  if (h == NULL)
+    {
+      _bfd_generic_link_add_one_symbol (info, abfd,
+                                        name,
+                                        BSF_GLOBAL,
+                                        sec,
+                                        value,
+                                        (const char*) NULL,
+                                        TRUE, FALSE, NULL);
+    }
+  else
+    {
+      h->root.type = bfd_link_hash_defined;
+      h->root.u.def.value = value;
+      h->root.u.def.section = sec;
+    }
+}
+
+
+/* Build all the stubs associated with the current output file.  The
+   stubs are kept in a hash table attached to the main linker hash
+   table.  This function is called via m68hc12elf_finish in the
+   linker.  */
+
+bfd_boolean
+elf32_m68hc11_build_stubs (abfd, info)
+     bfd* abfd;
+     struct bfd_link_info *info;
+{
+  asection *stub_sec;
+  struct bfd_hash_table *table;
+  struct m68hc11_elf_link_hash_table *htab;
+  struct m68hc11_scan_param param;
+
+  m68hc11_elf_get_bank_parameters (info);
+  htab = m68hc11_elf_hash_table (info);
+
+  for (stub_sec = htab->stub_bfd->sections;
+       stub_sec != NULL;
+       stub_sec = stub_sec->next)
+    {
+      bfd_size_type size;
+
+      /* Allocate memory to hold the linker stubs.  */
+      size = stub_sec->_raw_size;
+      stub_sec->contents = (unsigned char *) bfd_zalloc (htab->stub_bfd, size);
+      if (stub_sec->contents == NULL && size != 0)
+       return FALSE;
+      stub_sec->_raw_size = 0;
+    }
+
+  /* Build the stubs as directed by the stub hash table.  */
+  table = htab->stub_hash_table;
+  bfd_hash_traverse (table, m68hc11_elf_export_one_stub, info);
+  
+  /* Scan the output sections to see if we use the memory banks.
+     If so, export the symbols that define how the memory banks
+     are mapped.  This is used by gdb and the simulator to obtain
+     the information.  It can be used by programs to burn the eprom
+     at the good addresses.  */
+  param.use_memory_banks = FALSE;
+  param.pinfo = &htab->pinfo;
+  bfd_map_over_sections (abfd, scan_sections_for_abi, &param);
+  if (param.use_memory_banks)
+    {
+      m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_START_NAME,
+                              htab->pinfo.bank_physical,
+                              bfd_abs_section_ptr);
+      m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_VIRTUAL_NAME,
+                              htab->pinfo.bank_virtual,
+                              bfd_abs_section_ptr);
+      m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_SIZE_NAME,
+                              htab->pinfo.bank_size,
+                              bfd_abs_section_ptr);
+    }
+
+  return TRUE;
+}
+
+void
+m68hc11_elf_get_bank_parameters (info)
+     struct bfd_link_info *info;
+{
+  unsigned i;
+  struct m68hc11_page_info *pinfo;
+  struct bfd_link_hash_entry *h;
+
+  pinfo = &m68hc11_elf_hash_table (info)->pinfo;
+  if (pinfo->bank_param_initialized)
+    return;
+
+  pinfo->bank_virtual = M68HC12_BANK_VIRT;
+  pinfo->bank_mask = M68HC12_BANK_MASK;
+  pinfo->bank_physical = M68HC12_BANK_BASE;
+  pinfo->bank_shift = M68HC12_BANK_SHIFT;
+  pinfo->bank_size = 1 << M68HC12_BANK_SHIFT;
+
+  h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_START_NAME,
+                            FALSE, FALSE, TRUE);
+  if (h != (struct bfd_link_hash_entry*) NULL
+      && h->type == bfd_link_hash_defined)
+    pinfo->bank_physical = (h->u.def.value
+                            + h->u.def.section->output_section->vma
+                            + h->u.def.section->output_offset);
+
+  h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_VIRTUAL_NAME,
+                            FALSE, FALSE, TRUE);
+  if (h != (struct bfd_link_hash_entry*) NULL
+      && h->type == bfd_link_hash_defined)
+    pinfo->bank_virtual = (h->u.def.value
+                           + h->u.def.section->output_section->vma
+                           + h->u.def.section->output_offset);
+
+  h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_SIZE_NAME,
+                            FALSE, FALSE, TRUE);
+  if (h != (struct bfd_link_hash_entry*) NULL
+      && h->type == bfd_link_hash_defined)
+    pinfo->bank_size = (h->u.def.value
+                        + h->u.def.section->output_section->vma
+                        + h->u.def.section->output_offset);
+
+  pinfo->bank_shift = 0;
+  for (i = pinfo->bank_size; i != 0; i >>= 1)
+    pinfo->bank_shift++;
+  pinfo->bank_shift--;
+  pinfo->bank_mask = (1 << pinfo->bank_shift) - 1;
+  pinfo->bank_physical_end = pinfo->bank_physical + pinfo->bank_size;
+  pinfo->bank_param_initialized = 1;
+
+  h = bfd_link_hash_lookup (info->hash, "__far_trampoline", FALSE,
+                            FALSE, TRUE);
+  if (h != (struct bfd_link_hash_entry*) NULL
+      && h->type == bfd_link_hash_defined)
+    pinfo->trampoline_addr = (h->u.def.value
+                              + h->u.def.section->output_section->vma
+                              + h->u.def.section->output_offset);
+}
+
+/* Return 1 if the address is in banked memory.
+   This can be applied to a virtual address and to a physical address.  */
+int
+m68hc11_addr_is_banked (pinfo, addr)
+     struct m68hc11_page_info *pinfo;
+     bfd_vma addr;
+{
+  if (addr >= pinfo->bank_virtual)
+    return 1;
+
+  if (addr >= pinfo->bank_physical && addr <= pinfo->bank_physical_end)
+    return 1;
+
+  return 0;
+}
+
+/* Return the physical address seen by the processor, taking
+   into account banked memory.  */
+bfd_vma
+m68hc11_phys_addr (pinfo, addr)
+     struct m68hc11_page_info *pinfo;
+     bfd_vma addr;
+{
+  if (addr < pinfo->bank_virtual)
+    return addr;
+
+  /* Map the address to the memory bank.  */
+  addr -= pinfo->bank_virtual;
+  addr &= pinfo->bank_mask;
+  addr += pinfo->bank_physical;
+  return addr;
+}
+
+/* Return the page number corresponding to an address in banked memory.  */
+bfd_vma
+m68hc11_phys_page (pinfo, addr)
+     struct m68hc11_page_info *pinfo;
+     bfd_vma addr;
+{
+  if (addr < pinfo->bank_virtual)
+    return 0;
+
+  /* Map the address to the memory bank.  */
+  addr -= pinfo->bank_virtual;
+  addr >>= pinfo->bank_shift;
+  addr &= 0x0ff;
+  return addr;
+}
+
+/* This function is used for relocs which are only used for relaxing,
+   which the linker should otherwise ignore.  */
+
+bfd_reloc_status_type
+m68hc11_elf_ignore_reloc (abfd, reloc_entry, symbol, data, input_section,
+                          output_bfd, error_message)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *reloc_entry;
+     asymbol *symbol ATTRIBUTE_UNUSED;
+     PTR data ATTRIBUTE_UNUSED;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  if (output_bfd != NULL)
+    reloc_entry->address += input_section->output_offset;
+  return bfd_reloc_ok;
+}
+
+bfd_reloc_status_type
+m68hc11_elf_special_reloc (abfd, reloc_entry, symbol, data, input_section,
+                           output_bfd, error_message)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data ATTRIBUTE_UNUSED;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  if (output_bfd != (bfd *) NULL
+      && (symbol->flags & BSF_SECTION_SYM) == 0
+      && (! reloc_entry->howto->partial_inplace
+         || reloc_entry->addend == 0))
+    {
+      reloc_entry->address += input_section->output_offset;
+      return bfd_reloc_ok;
+    }
+
+  if (output_bfd != NULL)
+    return bfd_reloc_continue;
+
+  if (reloc_entry->address > input_section->_cooked_size)
+    return bfd_reloc_outofrange;
+
+  abort();
+}
+
+asection *
+elf32_m68hc11_gc_mark_hook (sec, info, rel, h, sym)
+     asection *sec;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     Elf_Internal_Rela *rel;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  if (h != NULL)
+    {
+      switch (ELF32_R_TYPE (rel->r_info))
+       {
+       default:
+         switch (h->root.type)
+           {
+           case bfd_link_hash_defined:
+           case bfd_link_hash_defweak:
+             return h->root.u.def.section;
+
+           case bfd_link_hash_common:
+             return h->root.u.c.p->section;
+
+           default:
+             break;
+           }
+       }
+    }
+  else
+    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+
+  return NULL;
+}
+
+bfd_boolean
+elf32_m68hc11_gc_sweep_hook (abfd, info, sec, relocs)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     asection *sec ATTRIBUTE_UNUSED;
+     const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
+{
+  /* We don't use got and plt entries for 68hc11/68hc12.  */
+  return TRUE;
+}
+
+/* Look through the relocs for a section during the first phase.
+   Since we don't do .gots or .plts, we just need to consider the
+   virtual table relocs for gc.  */
+
+bfd_boolean
+elf32_m68hc11_check_relocs (abfd, info, sec, relocs)
+     bfd * abfd;
+     struct bfd_link_info * info;
+     asection * sec;
+     const Elf_Internal_Rela * relocs;
+{
+  Elf_Internal_Shdr *           symtab_hdr;
+  struct elf_link_hash_entry ** sym_hashes;
+  struct elf_link_hash_entry ** sym_hashes_end;
+  const Elf_Internal_Rela *     rel;
+  const Elf_Internal_Rela *     rel_end;
+
+  if (info->relocateable)
+    return TRUE;
+
+  symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
+  if (!elf_bad_symtab (abfd))
+    sym_hashes_end -= symtab_hdr->sh_info;
+
+  rel_end = relocs + sec->reloc_count;
+
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      struct elf_link_hash_entry * h;
+      unsigned long r_symndx;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+
+      if (r_symndx < symtab_hdr->sh_info)
+        h = NULL;
+      else
+        h = sym_hashes [r_symndx - symtab_hdr->sh_info];
+
+      switch (ELF32_R_TYPE (rel->r_info))
+        {
+        /* This relocation describes the C++ object vtable hierarchy.
+           Reconstruct it for later use during GC.  */
+        case R_M68HC11_GNU_VTINHERIT:
+          if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+            return FALSE;
+          break;
+
+        /* This relocation describes which C++ vtable entries are actually
+           used.  Record for later use during GC.  */
+        case R_M68HC11_GNU_VTENTRY:
+          if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+            return FALSE;
+          break;
+        }
+    }
+
+  return TRUE;
+}
+
+static bfd_boolean
+m68hc11_get_relocation_value (abfd, info, local_sections, local_syms,
+                              rel, name,
+                              relocation, is_far)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection **local_sections;
+     Elf_Internal_Sym* local_syms;
+     Elf_Internal_Rela* rel;
+     const char** name;
+     bfd_vma* relocation;
+     bfd_boolean* is_far;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  unsigned long r_symndx;
+  asection *sec;
+  struct elf_link_hash_entry *h;
+  Elf_Internal_Sym *sym;
+  const char* stub_name = 0;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+
+  r_symndx = ELF32_R_SYM (rel->r_info);
+
+  /* This is a final link.  */
+  h = NULL;
+  sym = NULL;
+  sec = NULL;
+  if (r_symndx < symtab_hdr->sh_info)
+    {
+      sym = local_syms + r_symndx;
+      sec = local_sections[r_symndx];
+      *relocation = (sec->output_section->vma
+                     + sec->output_offset
+                     + sym->st_value);
+      *is_far = (sym && (sym->st_other & STO_M68HC12_FAR));
+      if (*is_far)
+        stub_name = (bfd_elf_string_from_elf_section
+                     (abfd, symtab_hdr->sh_link,
+                      sym->st_name));
+    }
+  else
+    {
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      while (h->root.type == bfd_link_hash_indirect
+             || h->root.type == bfd_link_hash_warning)
+        h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      if (h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+        {
+          sec = h->root.u.def.section;
+          *relocation = (h->root.u.def.value
+                         + sec->output_section->vma
+                         + sec->output_offset);
+        }
+      else if (h->root.type == bfd_link_hash_undefweak)
+        *relocation = 0;
+      else
+        {
+          if (!((*info->callbacks->undefined_symbol)
+                (info, h->root.root.string, abfd,
+                 sec, rel->r_offset, TRUE)))
+            return FALSE;
+          *relocation = 0;
+        }
+      *is_far = (h && (h->other & STO_M68HC12_FAR));
+      stub_name = h->root.root.string;
+    }
+
+  if (h != NULL)
+    *name = h->root.root.string;
+  else
+    {
+      *name = (bfd_elf_string_from_elf_section
+               (abfd, symtab_hdr->sh_link, sym->st_name));
+      if (*name == NULL || **name == '\0')
+        *name = bfd_section_name (input_bfd, sec);
+    }
+
+  if (*is_far && ELF32_R_TYPE (rel->r_info) == R_M68HC11_16)
+    {
+      struct elf32_m68hc11_stub_hash_entry* stub;
+      struct m68hc11_elf_link_hash_table *htab;
+
+      htab = m68hc11_elf_hash_table (info);
+      stub = m68hc12_stub_hash_lookup (htab->stub_hash_table,
+                                       *name, FALSE, FALSE);
+      if (stub)
+        {
+          *relocation = stub->stub_offset
+            + stub->stub_sec->output_section->vma
+            + stub->stub_sec->output_offset;
+          *is_far = FALSE;
+        }
+    }
+  return TRUE;
+}
+
+/* Relocate a 68hc11/68hc12 ELF section.  */
+bfd_boolean
+elf32_m68hc11_relocate_section (output_bfd, info, input_bfd, input_section,
+                                contents, relocs, local_syms, local_sections)
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     asection *input_section;
+     bfd_byte *contents;
+     Elf_Internal_Rela *relocs;
+     Elf_Internal_Sym *local_syms;
+     asection **local_sections;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  Elf_Internal_Rela *rel, *relend;
+  const char *name;
+  struct m68hc11_page_info *pinfo;
+  struct elf_backend_data * const ebd = get_elf_backend_data (input_bfd);
+
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (input_bfd);
+
+  /* Get memory bank parameters.  */
+  m68hc11_elf_get_bank_parameters (info);
+  pinfo = &m68hc11_elf_hash_table (info)->pinfo;
+
+  rel = relocs;
+  relend = relocs + input_section->reloc_count;
+  for (; rel < relend; rel++)
+    {
+      int r_type;
+      arelent arel;
+      reloc_howto_type *howto;
+      unsigned long r_symndx;
+      Elf_Internal_Sym *sym;
+      asection *sec;
+      bfd_vma relocation;
+      bfd_reloc_status_type r = bfd_reloc_undefined;
+      bfd_vma phys_page;
+      bfd_vma phys_addr;
+      bfd_vma insn_addr;
+      bfd_vma insn_page;
+      bfd_boolean is_far;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      r_type = ELF32_R_TYPE (rel->r_info);
+
+      if (r_type == R_M68HC11_GNU_VTENTRY
+          || r_type == R_M68HC11_GNU_VTINHERIT )
+        continue;
+
+      if (info->relocateable)
+       {
+         /* This is a relocateable link.  We don't have to change
+            anything, unless the reloc is against a section symbol,
+            in which case we have to adjust according to where the
+            section symbol winds up in the output section.  */
+         if (r_symndx < symtab_hdr->sh_info)
+           {
+             sym = local_syms + r_symndx;
+             if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+               {
+                 sec = local_sections[r_symndx];
+                 rel->r_addend += sec->output_offset + sym->st_value;
+               }
+           }
+
+         continue;
+       }
+      (*ebd->elf_info_to_howto_rel) (input_bfd, &arel, rel);
+      howto = arel.howto;
+
+      m68hc11_get_relocation_value (input_bfd, info,
+                                    local_sections, local_syms,
+                                    rel, &name, &relocation, &is_far);
+
+      /* Do the memory bank mapping.  */
+      phys_addr = m68hc11_phys_addr (pinfo, relocation + rel->r_addend);
+      phys_page = m68hc11_phys_page (pinfo, relocation + rel->r_addend);
+      switch (r_type)
+        {
+        case R_M68HC11_24:
+          /* Reloc used by 68HC12 call instruction.  */
+          bfd_put_16 (input_bfd, phys_addr,
+                      (bfd_byte*) contents + rel->r_offset);
+          bfd_put_8 (input_bfd, phys_page,
+                     (bfd_byte*) contents + rel->r_offset + 2);
+          r = bfd_reloc_ok;
+          r_type = R_M68HC11_NONE;
+          break;
+
+        case R_M68HC11_NONE:
+          r = bfd_reloc_ok;
+          break;
+
+        case R_M68HC11_LO16:
+          /* Reloc generated by %addr(expr) gas to obtain the
+             address as mapped in the memory bank window.  */
+          relocation = phys_addr;
+          break;
+
+        case R_M68HC11_PAGE:
+          /* Reloc generated by %page(expr) gas to obtain the
+             page number associated with the address.  */
+          relocation = phys_page;
+          break;
+
+        case R_M68HC11_16:
+          /* Get virtual address of instruction having the relocation.  */
+          if (is_far)
+            {
+              const char* msg;
+              char* buf;
+              msg = _("Reference to the far symbol `%s' using a wrong "
+                      "relocation may result in incorrect execution");
+              buf = alloca (strlen (msg) + strlen (name) + 10);
+              sprintf (buf, msg, name);
+              
+              (* info->callbacks->warning)
+                (info, buf, name, input_bfd, NULL, rel->r_offset);
+            }
+
+          /* Get virtual address of instruction having the relocation.  */
+          insn_addr = input_section->output_section->vma
+            + input_section->output_offset
+            + rel->r_offset;
+
+          insn_page = m68hc11_phys_page (pinfo, insn_addr);
+
+          if (m68hc11_addr_is_banked (pinfo, relocation + rel->r_addend)
+              && m68hc11_addr_is_banked (pinfo, insn_addr)
+              && phys_page != insn_page)
+            {
+              const char* msg;
+              char* buf;
+
+              msg = _("banked address [%lx:%04lx] (%lx) is not in the same bank "
+                      "as current banked address [%lx:%04lx] (%lx)");
+
+              buf = alloca (strlen (msg) + 128);
+              sprintf (buf, msg, phys_page, phys_addr,
+                       (long) (relocation + rel->r_addend),
+                       insn_page, m68hc11_phys_addr (pinfo, insn_addr),
+                       (long) (insn_addr));
+              if (!((*info->callbacks->warning)
+                    (info, buf, name, input_bfd, input_section,
+                     rel->r_offset)))
+                return FALSE;
+              break;
+            }
+          if (phys_page != 0 && insn_page == 0)
+            {
+              const char* msg;
+              char* buf;
+
+              msg = _("reference to a banked address [%lx:%04lx] in the "
+                      "normal address space at %04lx");
+
+              buf = alloca (strlen (msg) + 128);
+              sprintf (buf, msg, phys_page, phys_addr, insn_addr);
+              if (!((*info->callbacks->warning)
+                    (info, buf, name, input_bfd, input_section,
+                     insn_addr)))
+                return FALSE;
+
+              relocation = phys_addr;
+              break;
+            }
+
+          /* If this is a banked address use the phys_addr so that
+             we stay in the banked window.  */
+          if (m68hc11_addr_is_banked (pinfo, relocation + rel->r_addend))
+            relocation = phys_addr;
+          break;
+        }
+      if (r_type != R_M68HC11_NONE)
+        r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                      contents, rel->r_offset,
+                                      relocation, rel->r_addend);
+
+      if (r != bfd_reloc_ok)
+       {
+         const char * msg = (const char *) 0;
+
+         switch (r)
+           {
+           case bfd_reloc_overflow:
+             if (!((*info->callbacks->reloc_overflow)
+                   (info, name, howto->name, (bfd_vma) 0,
+                    input_bfd, input_section, rel->r_offset)))
+               return FALSE;
+             break;
+
+           case bfd_reloc_undefined:
+             if (!((*info->callbacks->undefined_symbol)
+                   (info, name, input_bfd, input_section,
+                    rel->r_offset, TRUE)))
+               return FALSE;
+             break;
+
+           case bfd_reloc_outofrange:
+             msg = _ ("internal error: out of range error");
+             goto common_error;
+
+           case bfd_reloc_notsupported:
+             msg = _ ("internal error: unsupported relocation error");
+             goto common_error;
+
+           case bfd_reloc_dangerous:
+             msg = _ ("internal error: dangerous error");
+             goto common_error;
+
+           default:
+             msg = _ ("internal error: unknown error");
+             /* fall through */
+
+           common_error:
+             if (!((*info->callbacks->warning)
+                   (info, msg, name, input_bfd, input_section,
+                    rel->r_offset)))
+               return FALSE;
+             break;
+           }
+       }
+    }
+
+  return TRUE;
+}
+
+
+\f
+/* Set and control ELF flags in ELF header.  */
+
+bfd_boolean
+_bfd_m68hc11_elf_set_private_flags (abfd, flags)
+     bfd *abfd;
+     flagword flags;
+{
+  BFD_ASSERT (!elf_flags_init (abfd)
+             || elf_elfheader (abfd)->e_flags == flags);
+
+  elf_elfheader (abfd)->e_flags = flags;
+  elf_flags_init (abfd) = TRUE;
+  return TRUE;
+}
+
+/* Merge backend specific data from an object file to the output
+   object file when linking.  */
+
+bfd_boolean
+_bfd_m68hc11_elf_merge_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  flagword old_flags;
+  flagword new_flags;
+  bfd_boolean ok = TRUE;
+
+  /* Check if we have the same endianess */
+  if (!_bfd_generic_verify_endian_match (ibfd, obfd))
+    return FALSE;
+
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  new_flags = elf_elfheader (ibfd)->e_flags;
+  elf_elfheader (obfd)->e_flags |= new_flags & EF_M68HC11_ABI;
+  old_flags = elf_elfheader (obfd)->e_flags;
+
+  if (! elf_flags_init (obfd))
+    {
+      elf_flags_init (obfd) = TRUE;
+      elf_elfheader (obfd)->e_flags = new_flags;
+      elf_elfheader (obfd)->e_ident[EI_CLASS]
+       = elf_elfheader (ibfd)->e_ident[EI_CLASS];
+
+      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+         && bfd_get_arch_info (obfd)->the_default)
+       {
+         if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
+                                  bfd_get_mach (ibfd)))
+           return FALSE;
+       }
+
+      return TRUE;
+    }
+
+  /* Check ABI compatibility.  */
+  if ((new_flags & E_M68HC11_I32) != (old_flags & E_M68HC11_I32))
+    {
+      (*_bfd_error_handler)
+       (_("%s: linking files compiled for 16-bit integers (-mshort) "
+           "and others for 32-bit integers"),
+        bfd_archive_filename (ibfd));
+      ok = FALSE;
+    }
+  if ((new_flags & E_M68HC11_F64) != (old_flags & E_M68HC11_F64))
+    {
+      (*_bfd_error_handler)
+       (_("%s: linking files compiled for 32-bit double (-fshort-double) "
+           "and others for 64-bit double"),
+        bfd_archive_filename (ibfd));
+      ok = FALSE;
+    }
+  new_flags &= ~EF_M68HC11_ABI;
+  old_flags &= ~EF_M68HC11_ABI;
+
+  /* Warn about any other mismatches */
+  if (new_flags != old_flags)
+    {
+      (*_bfd_error_handler)
+       (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
+        bfd_archive_filename (ibfd), (unsigned long) new_flags,
+        (unsigned long) old_flags);
+      ok = FALSE;
+    }
+
+  if (! ok)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+bfd_boolean
+_bfd_m68hc11_elf_print_private_bfd_data (abfd, ptr)
+     bfd *abfd;
+     PTR ptr;
+{
+  FILE *file = (FILE *) ptr;
+
+  BFD_ASSERT (abfd != NULL && ptr != NULL);
+
+  /* Print normal ELF private data.  */
+  _bfd_elf_print_private_bfd_data (abfd, ptr);
+
+  /* xgettext:c-format */
+  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
+
+  if (elf_elfheader (abfd)->e_flags & E_M68HC11_I32)
+    fprintf (file, _("[abi=32-bit int, "));
+  else
+    fprintf (file, _("[abi=16-bit int, "));
+
+  if (elf_elfheader (abfd)->e_flags & E_M68HC11_F64)
+    fprintf (file, _("64-bit double, "));
+  else
+    fprintf (file, _("32-bit double, "));
+
+  if (strcmp (bfd_get_target (abfd), "elf32-m68hc11") == 0)
+    fprintf (file, _("cpu=HC11]"));
+  else if (elf_elfheader (abfd)->e_flags & EF_M68HCS12_MACH)
+    fprintf (file, _("cpu=HCS12]"));
+  else
+    fprintf (file, _("cpu=HC12]"));    
+
+  if (elf_elfheader (abfd)->e_flags & E_M68HC12_BANKS)
+    fprintf (file, _(" [memory=bank-model]"));
+  else
+    fprintf (file, _(" [memory=flat]"));
+
+  fputc ('\n', file);
+
+  return TRUE;
+}
+
+static void scan_sections_for_abi (abfd, asect, arg)
+     bfd* abfd ATTRIBUTE_UNUSED;
+     asection* asect;
+     PTR arg;
+{
+  struct m68hc11_scan_param* p = (struct m68hc11_scan_param*) arg;
+
+  if (asect->vma >= p->pinfo->bank_virtual)
+    p->use_memory_banks = TRUE;
+}
+  
+/* Tweak the OSABI field of the elf header.  */
+
+void
+elf32_m68hc11_post_process_headers (abfd, link_info)
+     bfd *abfd;
+     struct bfd_link_info *link_info;
+{
+  struct m68hc11_scan_param param;
+
+  if (link_info == 0)
+    return;
+
+  m68hc11_elf_get_bank_parameters (link_info);
+
+  param.use_memory_banks = FALSE;
+  param.pinfo = &m68hc11_elf_hash_table (link_info)->pinfo;
+  bfd_map_over_sections (abfd, scan_sections_for_abi, &param);
+  if (param.use_memory_banks)
+    {
+      Elf_Internal_Ehdr * i_ehdrp;
+
+      i_ehdrp = elf_elfheader (abfd);
+      i_ehdrp->e_flags |= E_M68HC12_BANKS;
+    }
+}
+
diff --git a/bfd/elf32-m68hc1x.h b/bfd/elf32-m68hc1x.h
new file mode 100644 (file)
index 0000000..e70c172
--- /dev/null
@@ -0,0 +1,205 @@
+/* Motorola 68HC11/68HC12-specific support for 32-bit ELF
+   Copyright 2003 Free Software Foundation, Inc.
+   Contributed by Stephane Carrez (stcarrez@nerim.fr)
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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
+(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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _ELF32_M68HC1X_H
+#define _ELF32_M68HC1X_H
+
+#include "elf-bfd.h"
+#include "bfdlink.h"
+#include "elf/m68hc11.h"
+
+/* Name of symbols exported by HC11/HC12 linker when there is a memory
+   bank window.  */
+#define BFD_M68HC11_BANK_START_NAME   "__bank_start"
+#define BFD_M68HC11_BANK_SIZE_NAME    "__bank_size"
+#define BFD_M68HC11_BANK_VIRTUAL_NAME "__bank_virtual"
+
+/* Set and control ELF flags in ELF header.  */
+extern bfd_boolean _bfd_m68hc11_elf_merge_private_bfd_data PARAMS ((bfd*,bfd*));
+extern bfd_boolean _bfd_m68hc11_elf_set_private_flags PARAMS ((bfd*,flagword));
+extern bfd_boolean _bfd_m68hc11_elf_print_private_bfd_data PARAMS ((bfd*,PTR));
+
+/* This hash entry is used to record a trampoline that must be generated
+   to call a far function using a normal calling convention ('jsr').
+   The trampoline is used when a pointer to a far function is used.
+   It takes care of installing the proper memory bank as well as creating
+   the 'call/rtc' calling convention.  */
+struct elf32_m68hc11_stub_hash_entry {
+
+  /* Base hash table entry structure.  */
+  struct bfd_hash_entry root;
+
+  /* The stub section.  */
+  asection *stub_sec;
+
+  /* Offset within stub_sec of the beginning of this stub.  */
+  bfd_vma stub_offset;
+
+  /* Given the symbol's value and its section we can determine its final
+     value when building the stubs (so the stub knows where to jump.  */
+  bfd_vma target_value;
+  asection *target_section;
+};
+
+/* Placeholder for the parameters to compute memory page and physical address.
+   The following formulas are used:
+
+   sym > bank_virtual =>
+     %addr(sym) = (((sym - bank_virtual) & bank_mask) + bank_physical
+     %page(sym) = (((sym - bank_virtual) >> bank_shift) % 256
+
+   sym < bank_virtual =>
+     %addr(sym) = sym
+     %page(sym) = 0
+
+
+   These parameters are obtained from the symbol table by looking
+   at the following:
+
+   __bank_start         Symbol marking the start of memory bank window
+                        (bank_physical)
+   __bank_virtual       Logical address of symbols for which the transformation
+                        must be computed
+   __bank_page_size     Size in bytes of page size (this is *NOT* the memory
+                        bank window size and the window size is always
+                        less or equal to the page size)
+
+   For 68HC12, the window is at 0x8000 and the page size is 16K (full window).
+   For 68HC11 this is board specific (implemented by external hardware).
+
+*/
+struct m68hc11_page_info
+{
+  bfd_vma bank_virtual;
+  bfd_vma bank_physical;
+  bfd_vma bank_physical_end;
+  bfd_vma bank_mask;
+  bfd_vma bank_size;
+  int bank_shift;
+  int bank_param_initialized;
+  bfd_vma trampoline_addr;
+};
+
+struct m68hc11_elf_link_hash_table
+{
+  struct elf_link_hash_table root;
+  struct m68hc11_page_info pinfo;
+
+  /* The stub hash table.  */
+  struct bfd_hash_table* stub_hash_table;
+
+  /* Linker stub bfd.  */
+  bfd *stub_bfd;
+
+  asection* stub_section;
+  asection* tramp_section;
+
+  /* Linker call-backs.  */
+  asection * (*add_stub_section) PARAMS ((const char *, asection *));
+
+  /* Assorted information used by elf32_hppa_size_stubs.  */
+  unsigned int bfd_count;
+  int top_index;
+  asection **input_list;
+  Elf_Internal_Sym **all_local_syms;
+
+  /* Small local sym to section mapping cache.  */
+  struct sym_sec_cache sym_sec;
+
+  bfd_boolean (* size_one_stub) PARAMS((struct bfd_hash_entry*, PTR));
+  bfd_boolean (* build_one_stub) PARAMS((struct bfd_hash_entry*, PTR));
+};
+
+/* Get the Sparc64 ELF linker hash table from a link_info structure.  */
+
+#define m68hc11_elf_hash_table(p) \
+  ((struct m68hc11_elf_link_hash_table *) ((p)->hash))
+
+/* Create a 68HC11/68HC12 ELF linker hash table.  */
+
+extern struct m68hc11_elf_link_hash_table* m68hc11_elf_hash_table_create
+  PARAMS ((bfd*));
+extern void m68hc11_elf_bfd_link_hash_table_free
+  PARAMS ((struct bfd_link_hash_table*));
+
+extern void m68hc11_elf_get_bank_parameters
+  PARAMS ((struct bfd_link_info*));
+
+/* Return 1 if the address is in banked memory.
+   This can be applied to a virtual address and to a physical address.  */
+extern int m68hc11_addr_is_banked
+  PARAMS ((struct m68hc11_page_info*, bfd_vma));
+
+/* Return the physical address seen by the processor, taking
+   into account banked memory.  */
+extern bfd_vma m68hc11_phys_addr
+  PARAMS ((struct m68hc11_page_info*, bfd_vma));
+
+/* Return the page number corresponding to an address in banked memory.  */
+extern bfd_vma m68hc11_phys_page
+  PARAMS ((struct m68hc11_page_info*, bfd_vma));
+
+bfd_reloc_status_type m68hc11_elf_ignore_reloc
+  PARAMS ((bfd *abfd, arelent *reloc_entry,
+           asymbol *symbol, PTR data, asection *input_section,
+           bfd *output_bfd, char **error_message));
+bfd_reloc_status_type m68hc11_elf_special_reloc
+  PARAMS ((bfd *abfd, arelent *reloc_entry,
+           asymbol *symbol, PTR data, asection *input_section,
+           bfd *output_bfd, char **error_message));
+
+/* GC mark and sweep.  */
+asection *elf32_m68hc11_gc_mark_hook
+  PARAMS ((asection *sec, struct bfd_link_info *info,
+           Elf_Internal_Rela *rel, struct elf_link_hash_entry *h,
+           Elf_Internal_Sym *sym));
+bfd_boolean elf32_m68hc11_gc_sweep_hook
+  PARAMS ((bfd *abfd, struct bfd_link_info *info,
+           asection *sec, const Elf_Internal_Rela *relocs));
+bfd_boolean elf32_m68hc11_check_relocs
+  PARAMS ((bfd * abfd, struct bfd_link_info * info,
+           asection * sec, const Elf_Internal_Rela * relocs));
+bfd_boolean elf32_m68hc11_relocate_section
+  PARAMS ((bfd *output_bfd, struct bfd_link_info *info,
+           bfd *input_bfd, asection *input_section,
+           bfd_byte *contents, Elf_Internal_Rela *relocs,
+           Elf_Internal_Sym *local_syms, asection **local_sections));
+
+bfd_boolean elf32_m68hc11_add_symbol_hook
+  PARAMS ((bfd *abfd, struct bfd_link_info *info,
+           const Elf_Internal_Sym *sym, const char **namep,
+           flagword *flagsp, asection **secp,
+           bfd_vma *valp));
+
+/* Tweak the OSABI field of the elf header.  */
+
+extern void elf32_m68hc11_post_process_headers
+  PARAMS ((bfd*, struct bfd_link_info*));
+
+int elf32_m68hc11_setup_section_lists
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+bfd_boolean elf32_m68hc11_size_stubs
+  PARAMS ((bfd *, bfd *, struct bfd_link_info *,
+          asection * (*) PARAMS ((const char *, asection *))));
+
+bfd_boolean elf32_m68hc11_build_stubs
+  PARAMS ((bfd* abfd, struct bfd_link_info *));
+#endif
diff --git a/gdb/gdb_gcore.sh b/gdb/gdb_gcore.sh
new file mode 100755 (executable)
index 0000000..9b42808
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+#   Copyright 2003  Free Software Foundation, Inc.
+
+# 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
+# (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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+#
+# gcore.sh
+# Script to generate a core file of a running program.
+# It starts up gdb, attaches to the given PID and invokes the gcore command.
+#
+
+if [ "$#" -eq "0" ]
+then
+    echo "usage:  gcore [-o filename] pid"
+    exit 2
+fi
+
+# Need to check for -o option, but set default basename to "core".
+name=core
+
+if [ "$1" = "-o" ]
+then
+    if [ "$#" -lt "3" ]
+    then
+       # Not enough arguments.
+       echo "usage:  gcore [-o filename] pid"
+       exit 2
+    fi
+    name=$2
+
+    # Shift over to start of pid list
+    shift; shift
+fi
+
+# Initialise return code.
+rc=0
+
+# Loop through pids
+for pid in $*
+do
+       # Write gdb script for pid $pid.  
+
+       # Avoid need for temporary files by using funky "here
+       # document" feature of sh.
+
+       /usr/bin/gdb > /dev/null << EOF
+       attach $pid
+       gcore $name.$pid
+       detach
+       quit
+EOF
+
+       if [ -r $name.$pid ] ; then 
+           rc=0
+       else
+           echo gcore: failed to create $name.$pid
+           rc=1
+           break
+       fi
+
+
+done
+
+exit $rc
+
diff --git a/gdb/infcall.c b/gdb/infcall.c
new file mode 100644 (file)
index 0000000..1ce22fb
--- /dev/null
@@ -0,0 +1,981 @@
+/* Perform an inferior function call, for GDB, the GNU debugger.
+
+   Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+   1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 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
+   (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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "breakpoint.h"
+#include "target.h"
+#include "regcache.h"
+#include "inferior.h"
+#include "gdb_assert.h"
+#include "block.h"
+#include "gdbcore.h"
+#include "language.h"
+#include "symfile.h"
+#include "gdbcmd.h"
+#include "command.h"
+#include "gdb_string.h"
+
+/* NOTE: cagney/2003-04-16: What's the future of this code?
+
+   GDB needs an asynchronous expression evaluator, that means an
+   asynchronous inferior function call implementation, and that in
+   turn means restructuring the code so that it is event driven.  */
+
+/* How you should pass arguments to a function depends on whether it
+   was defined in K&R style or prototype style.  If you define a
+   function using the K&R syntax that takes a `float' argument, then
+   callers must pass that argument as a `double'.  If you define the
+   function using the prototype syntax, then you must pass the
+   argument as a `float', with no promotion.
+
+   Unfortunately, on certain older platforms, the debug info doesn't
+   indicate reliably how each function was defined.  A function type's
+   TYPE_FLAG_PROTOTYPED flag may be clear, even if the function was
+   defined in prototype style.  When calling a function whose
+   TYPE_FLAG_PROTOTYPED flag is clear, GDB consults this flag to
+   decide what to do.
+
+   For modern targets, it is proper to assume that, if the prototype
+   flag is clear, that can be trusted: `float' arguments should be
+   promoted to `double'.  For some older targets, if the prototype
+   flag is clear, that doesn't tell us anything.  The default is to
+   trust the debug information; the user can override this behavior
+   with "set coerce-float-to-double 0".  */
+
+static int coerce_float_to_double_p = 1;
+
+/* This boolean tells what gdb should do if a signal is received while
+   in a function called from gdb (call dummy).  If set, gdb unwinds
+   the stack and restore the context to what as it was before the
+   call.
+
+   The default is to stop in the frame where the signal was received. */
+
+int unwind_on_signal_p = 0;
+
+/* Perform the standard coercions that are specified
+   for arguments to be passed to C functions.
+
+   If PARAM_TYPE is non-NULL, it is the expected parameter type.
+   IS_PROTOTYPED is non-zero if the function declaration is prototyped.  */
+
+static struct value *
+value_arg_coerce (struct value *arg, struct type *param_type,
+                 int is_prototyped)
+{
+  register struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+  register struct type *type
+    = param_type ? check_typedef (param_type) : arg_type;
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_REF:
+      if (TYPE_CODE (arg_type) != TYPE_CODE_REF
+         && TYPE_CODE (arg_type) != TYPE_CODE_PTR)
+       {
+         arg = value_addr (arg);
+         VALUE_TYPE (arg) = param_type;
+         return arg;
+       }
+      break;
+    case TYPE_CODE_INT:
+    case TYPE_CODE_CHAR:
+    case TYPE_CODE_BOOL:
+    case TYPE_CODE_ENUM:
+      /* If we don't have a prototype, coerce to integer type if necessary.  */
+      if (!is_prototyped)
+       {
+         if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
+           type = builtin_type_int;
+       }
+      /* Currently all target ABIs require at least the width of an integer
+         type for an argument.  We may have to conditionalize the following
+         type coercion for future targets.  */
+      if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
+       type = builtin_type_int;
+      break;
+    case TYPE_CODE_FLT:
+      if (!is_prototyped && coerce_float_to_double_p)
+       {
+         if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_double))
+           type = builtin_type_double;
+         else if (TYPE_LENGTH (type) > TYPE_LENGTH (builtin_type_double))
+           type = builtin_type_long_double;
+       }
+      break;
+    case TYPE_CODE_FUNC:
+      type = lookup_pointer_type (type);
+      break;
+    case TYPE_CODE_ARRAY:
+      /* Arrays are coerced to pointers to their first element, unless
+         they are vectors, in which case we want to leave them alone,
+         because they are passed by value.  */
+      if (current_language->c_style_arrays)
+       if (!TYPE_VECTOR (type))
+         type = lookup_pointer_type (TYPE_TARGET_TYPE (type));
+      break;
+    case TYPE_CODE_UNDEF:
+    case TYPE_CODE_PTR:
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_VOID:
+    case TYPE_CODE_SET:
+    case TYPE_CODE_RANGE:
+    case TYPE_CODE_STRING:
+    case TYPE_CODE_BITSTRING:
+    case TYPE_CODE_ERROR:
+    case TYPE_CODE_MEMBER:
+    case TYPE_CODE_METHOD:
+    case TYPE_CODE_COMPLEX:
+    default:
+      break;
+    }
+
+  return value_cast (type, arg);
+}
+
+/* Determine a function's address and its return type from its value.
+   Calls error() if the function is not valid for calling.  */
+
+CORE_ADDR
+find_function_addr (struct value *function, struct type **retval_type)
+{
+  register struct type *ftype = check_typedef (VALUE_TYPE (function));
+  register enum type_code code = TYPE_CODE (ftype);
+  struct type *value_type;
+  CORE_ADDR funaddr;
+
+  /* If it's a member function, just look at the function
+     part of it.  */
+
+  /* Determine address to call.  */
+  if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
+    {
+      funaddr = VALUE_ADDRESS (function);
+      value_type = TYPE_TARGET_TYPE (ftype);
+    }
+  else if (code == TYPE_CODE_PTR)
+    {
+      funaddr = value_as_address (function);
+      ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
+      if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
+         || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+       {
+         funaddr = CONVERT_FROM_FUNC_PTR_ADDR (funaddr);
+         value_type = TYPE_TARGET_TYPE (ftype);
+       }
+      else
+       value_type = builtin_type_int;
+    }
+  else if (code == TYPE_CODE_INT)
+    {
+      /* Handle the case of functions lacking debugging info.
+         Their values are characters since their addresses are char */
+      if (TYPE_LENGTH (ftype) == 1)
+       funaddr = value_as_address (value_addr (function));
+      else
+       /* Handle integer used as address of a function.  */
+       funaddr = (CORE_ADDR) value_as_long (function);
+
+      value_type = builtin_type_int;
+    }
+  else
+    error ("Invalid data type for function to be called.");
+
+  *retval_type = value_type;
+  return funaddr;
+}
+
+/* Call breakpoint_auto_delete on the current contents of the bpstat
+   pointed to by arg (which is really a bpstat *).  */
+
+static void
+breakpoint_auto_delete_contents (void *arg)
+{
+  breakpoint_auto_delete (*(bpstat *) arg);
+}
+
+/* All this stuff with a dummy frame may seem unnecessarily complicated
+   (why not just save registers in GDB?).  The purpose of pushing a dummy
+   frame which looks just like a real frame is so that if you call a
+   function and then hit a breakpoint (get a signal, etc), "backtrace"
+   will look right.  Whether the backtrace needs to actually show the
+   stack at the time the inferior function was called is debatable, but
+   it certainly needs to not display garbage.  So if you are contemplating
+   making dummy frames be different from normal frames, consider that.  */
+
+/* Perform a function call in the inferior.
+   ARGS is a vector of values of arguments (NARGS of them).
+   FUNCTION is a value, the function to be called.
+   Returns a value representing what the function returned.
+   May fail to return, if a breakpoint or signal is hit
+   during the execution of the function.
+
+   ARGS is modified to contain coerced values. */
+
+struct value *
+call_function_by_hand (struct value *function, int nargs, struct value **args)
+{
+  register CORE_ADDR sp;
+  CORE_ADDR dummy_addr;
+  struct type *value_type;
+  unsigned char struct_return;
+  CORE_ADDR struct_addr = 0;
+  struct regcache *retbuf;
+  struct cleanup *retbuf_cleanup;
+  struct inferior_status *inf_status;
+  struct cleanup *inf_status_cleanup;
+  CORE_ADDR funaddr;
+  int using_gcc;               /* Set to version of gcc in use, or zero if not gcc */
+  CORE_ADDR real_pc;
+  struct type *ftype = check_typedef (SYMBOL_TYPE (function));
+  CORE_ADDR bp_addr;
+
+  if (!target_has_execution)
+    noprocess ();
+
+  /* Create a cleanup chain that contains the retbuf (buffer
+     containing the register values).  This chain is create BEFORE the
+     inf_status chain so that the inferior status can cleaned up
+     (restored or discarded) without having the retbuf freed.  */
+  retbuf = regcache_xmalloc (current_gdbarch);
+  retbuf_cleanup = make_cleanup_regcache_xfree (retbuf);
+
+  /* A cleanup for the inferior status.  Create this AFTER the retbuf
+     so that this can be discarded or applied without interfering with
+     the regbuf.  */
+  inf_status = save_inferior_status (1);
+  inf_status_cleanup = make_cleanup_restore_inferior_status (inf_status);
+
+  if (DEPRECATED_PUSH_DUMMY_FRAME_P ())
+    {
+      /* DEPRECATED_PUSH_DUMMY_FRAME is responsible for saving the
+        inferior registers (and frame_pop() for restoring them).  (At
+        least on most machines) they are saved on the stack in the
+        inferior.  */
+      DEPRECATED_PUSH_DUMMY_FRAME;
+    }
+  else
+    {
+      /* FIXME: cagney/2003-02-26: Step zero of this little tinker is
+      to extract the generic dummy frame code from the architecture
+      vector.  Hence this direct call.
+
+      A follow-on change is to modify this interface so that it takes
+      thread OR frame OR tpid as a parameter, and returns a dummy
+      frame handle.  The handle can then be used further down as a
+      parameter SAVE_DUMMY_FRAME_TOS.  Hmm, thinking about it, since
+      everything is ment to be using generic dummy frames, why not
+      even use some of the dummy frame code to here - do a regcache
+      dup and then pass the duped regcache, along with all the other
+      stuff, at one single point.
+
+      In fact, you can even save the structure's return address in the
+      dummy frame and fix one of those nasty lost struct return edge
+      conditions.  */
+      generic_push_dummy_frame ();
+    }
+
+  /* Ensure that the initial SP is correctly aligned.  */
+  {
+    CORE_ADDR old_sp = read_sp ();
+    if (gdbarch_frame_align_p (current_gdbarch))
+      {
+       /* NOTE: cagney/2002-09-18:
+          
+          On a RISC architecture, a void parameterless generic dummy
+          frame (i.e., no parameters, no result) typically does not
+          need to push anything the stack and hence can leave SP and
+          FP.  Similarly, a framelss (possibly leaf) function does
+          not push anything on the stack and, hence, that too can
+          leave FP and SP unchanged.  As a consequence, a sequence of
+          void parameterless generic dummy frame calls to frameless
+          functions will create a sequence of effectively identical
+          frames (SP, FP and TOS and PC the same).  This, not
+          suprisingly, results in what appears to be a stack in an
+          infinite loop --- when GDB tries to find a generic dummy
+          frame on the internal dummy frame stack, it will always
+          find the first one.
+
+          To avoid this problem, the code below always grows the
+          stack.  That way, two dummy frames can never be identical.
+          It does burn a few bytes of stack but that is a small price
+          to pay :-).  */
+       sp = gdbarch_frame_align (current_gdbarch, old_sp);
+       if (sp == old_sp)
+         {
+           if (INNER_THAN (1, 2))
+             /* Stack grows down.  */
+             sp = gdbarch_frame_align (current_gdbarch, old_sp - 1);
+           else
+             /* Stack grows up.  */
+             sp = gdbarch_frame_align (current_gdbarch, old_sp + 1);
+         }
+       gdb_assert ((INNER_THAN (1, 2) && sp <= old_sp)
+                   || (INNER_THAN (2, 1) && sp >= old_sp));
+      }
+    else
+      /* FIXME: cagney/2002-09-18: Hey, you loose!  Who knows how
+        badly aligned the SP is!  Further, per comment above, if the
+        generic dummy frame ends up empty (because nothing is pushed)
+        GDB won't be able to correctly perform back traces.  If a
+        target is having trouble with backtraces, first thing to do
+        is add FRAME_ALIGN() to its architecture vector.  After that,
+        try adding SAVE_DUMMY_FRAME_TOS() and modifying
+        DEPRECATED_FRAME_CHAIN so that when the next outer frame is a
+        generic dummy, it returns the current frame's base.  */
+      sp = old_sp;
+  }
+
+  funaddr = find_function_addr (function, &value_type);
+  CHECK_TYPEDEF (value_type);
+
+  {
+    struct block *b = block_for_pc (funaddr);
+    /* If compiled without -g, assume GCC 2.  */
+    using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
+  }
+
+  /* Are we returning a value using a structure return or a normal
+     value return? */
+
+  struct_return = using_struct_return (function, funaddr, value_type,
+                                      using_gcc);
+
+  switch (CALL_DUMMY_LOCATION)
+    {
+    case ON_STACK:
+      {
+       /* CALL_DUMMY is an array of words (REGISTER_SIZE), but each
+          word is in host byte order.  Before calling FIX_CALL_DUMMY,
+          we byteswap it and remove any extra bytes which might exist
+          because ULONGEST is bigger than REGISTER_SIZE.  */
+       /* NOTE: This is pretty wierd, as the call dummy is actually a
+          sequence of instructions.  But CISC machines will have to
+          pack the instructions into REGISTER_SIZE units (and so will
+          RISC machines for which INSTRUCTION_SIZE is not
+          REGISTER_SIZE).  */
+       /* NOTE: This is pretty stupid.  CALL_DUMMY should be in
+          strict target byte order. */
+       CORE_ADDR start_sp;
+       ULONGEST *dummy = alloca (SIZEOF_CALL_DUMMY_WORDS);
+       int sizeof_dummy1 = (REGISTER_SIZE * SIZEOF_CALL_DUMMY_WORDS
+                            / sizeof (ULONGEST));
+       char *dummy1 = alloca (sizeof_dummy1);
+       memcpy (dummy, CALL_DUMMY_WORDS, SIZEOF_CALL_DUMMY_WORDS);
+       if (INNER_THAN (1, 2))
+         {
+           /* Stack grows down */
+           sp -= sizeof_dummy1;
+           start_sp = sp;
+         }
+       else
+         {
+           /* Stack grows up */
+           start_sp = sp;
+           sp += sizeof_dummy1;
+         }
+       /* NOTE: cagney/2002-09-10: Don't bother re-adjusting the
+          stack after allocating space for the call dummy.  A target
+          can specify a SIZEOF_DUMMY1 (via SIZEOF_CALL_DUMMY_WORDS)
+          such that all local alignment requirements are met.  */
+       /* Create a call sequence customized for this function and the
+          number of arguments for it.  */
+       {
+         int i;
+         for (i = 0; i < (int) (SIZEOF_CALL_DUMMY_WORDS / sizeof (dummy[0]));
+              i++)
+           store_unsigned_integer (&dummy1[i * REGISTER_SIZE],
+                                   REGISTER_SIZE,
+                                   (ULONGEST) dummy[i]);
+       }
+       /* NOTE: cagney/2003-04-22: This computation of REAL_PC,
+          BP_ADDR and DUMMY_ADDR is pretty messed up.  It comes from
+          constant tinkering with the values.  Instead a
+          FIX_CALL_DUMMY replacement (PUSH_DUMMY_BREAKPOINT?) should
+          just do everything.  */
+#ifdef GDB_TARGET_IS_HPPA
+       real_pc = FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
+                                 value_type, using_gcc);
+#else
+       if (FIX_CALL_DUMMY_P ())
+         {
+           /* gdb_assert (CALL_DUMMY_LOCATION == ON_STACK) true?  */
+           FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args, value_type,
+                           using_gcc);
+         }
+       real_pc = start_sp;
+#endif
+       dummy_addr = start_sp;
+       /* Yes, the offset is applied to the real_pc and not the dummy
+          addr.  Ulgh!  Blame the HP/UX target.  */
+       bp_addr = real_pc + CALL_DUMMY_BREAKPOINT_OFFSET;
+       /* Yes, the offset is applied to the real_pc and not the
+          dummy_addr.  Ulgh!  Blame the HP/UX target.  */
+       real_pc += CALL_DUMMY_START_OFFSET;
+       write_memory (start_sp, (char *) dummy1, sizeof_dummy1);
+       if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
+         generic_save_call_dummy_addr (start_sp, start_sp + sizeof_dummy1);
+       break;
+      }
+    case AT_ENTRY_POINT:
+      real_pc = funaddr;
+      dummy_addr = CALL_DUMMY_ADDRESS ();
+      /* A call dummy always consists of just a single breakpoint, so
+         it's address is the same as the address of the dummy.  */
+      bp_addr = dummy_addr;
+      if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
+       /* NOTE: cagney/2002-04-13: The entry point is going to be
+           modified with a single breakpoint.  */
+       generic_save_call_dummy_addr (CALL_DUMMY_ADDRESS (),
+                                     CALL_DUMMY_ADDRESS () + 1);
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, "bad switch");
+    }
+
+  if (nargs < TYPE_NFIELDS (ftype))
+    error ("too few arguments in function call");
+
+  {
+    int i;
+    for (i = nargs - 1; i >= 0; i--)
+      {
+       int prototyped;
+       struct type *param_type;
+       
+       /* FIXME drow/2002-05-31: Should just always mark methods as
+          prototyped.  Can we respect TYPE_VARARGS?  Probably not.  */
+       if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+         prototyped = 1;
+       else if (i < TYPE_NFIELDS (ftype))
+         prototyped = TYPE_PROTOTYPED (ftype);
+       else
+         prototyped = 0;
+
+       if (i < TYPE_NFIELDS (ftype))
+         param_type = TYPE_FIELD_TYPE (ftype, i);
+       else
+         param_type = NULL;
+       
+       args[i] = value_arg_coerce (args[i], param_type, prototyped);
+
+       /* elz: this code is to handle the case in which the function
+          to be called has a pointer to function as parameter and the
+          corresponding actual argument is the address of a function
+          and not a pointer to function variable.  In aCC compiled
+          code, the calls through pointers to functions (in the body
+          of the function called by hand) are made via
+          $$dyncall_external which requires some registers setting,
+          this is taken care of if we call via a function pointer
+          variable, but not via a function address.  In cc this is
+          not a problem. */
+
+       if (using_gcc == 0)
+         {
+           if (param_type != NULL && TYPE_CODE (ftype) != TYPE_CODE_METHOD)
+             {
+               /* if this parameter is a pointer to function.  */
+               if (TYPE_CODE (param_type) == TYPE_CODE_PTR)
+                 if (TYPE_CODE (TYPE_TARGET_TYPE (param_type)) == TYPE_CODE_FUNC)
+                   /* elz: FIXME here should go the test about the
+                      compiler used to compile the target. We want to
+                      issue the error message only if the compiler
+                      used was HP's aCC.  If we used HP's cc, then
+                      there is no problem and no need to return at
+                      this point.  */
+                   /* Go see if the actual parameter is a variable of
+                      type pointer to function or just a function.  */
+                   if (args[i]->lval == not_lval)
+                     {
+                       char *arg_name;
+                       if (find_pc_partial_function ((CORE_ADDR) args[i]->aligner.contents[0], &arg_name, NULL, NULL))
+                         error ("\
+You cannot use function <%s> as argument. \n\
+You must use a pointer to function type variable. Command ignored.", arg_name);
+                     }
+             }
+         }
+      }
+  }
+
+  if (REG_STRUCT_HAS_ADDR_P ())
+    {
+      int i;
+      /* This is a machine like the sparc, where we may need to pass a
+        pointer to the structure, not the structure itself.  */
+      for (i = nargs - 1; i >= 0; i--)
+       {
+         struct type *arg_type = check_typedef (VALUE_TYPE (args[i]));
+         if ((TYPE_CODE (arg_type) == TYPE_CODE_STRUCT
+              || TYPE_CODE (arg_type) == TYPE_CODE_UNION
+              || TYPE_CODE (arg_type) == TYPE_CODE_ARRAY
+              || TYPE_CODE (arg_type) == TYPE_CODE_STRING
+              || TYPE_CODE (arg_type) == TYPE_CODE_BITSTRING
+              || TYPE_CODE (arg_type) == TYPE_CODE_SET
+              || (TYPE_CODE (arg_type) == TYPE_CODE_FLT
+                  && TYPE_LENGTH (arg_type) > 8)
+              )
+             && REG_STRUCT_HAS_ADDR (using_gcc, arg_type))
+           {
+             CORE_ADDR addr;
+             int len;          /*  = TYPE_LENGTH (arg_type); */
+             int aligned_len;
+             arg_type = check_typedef (VALUE_ENCLOSING_TYPE (args[i]));
+             len = TYPE_LENGTH (arg_type);
+
+             if (STACK_ALIGN_P ())
+               /* MVS 11/22/96: I think at least some of this
+                  stack_align code is really broken.  Better to let
+                  PUSH_ARGUMENTS adjust the stack in a target-defined
+                  manner.  */
+               aligned_len = STACK_ALIGN (len);
+             else
+               aligned_len = len;
+             if (INNER_THAN (1, 2))
+               {
+                 /* stack grows downward */
+                 sp -= aligned_len;
+                 /* ... so the address of the thing we push is the
+                    stack pointer after we push it.  */
+                 addr = sp;
+               }
+             else
+               {
+                 /* The stack grows up, so the address of the thing
+                    we push is the stack pointer before we push it.  */
+                 addr = sp;
+                 sp += aligned_len;
+               }
+             /* Push the structure.  */
+             write_memory (addr, VALUE_CONTENTS_ALL (args[i]), len);
+             /* The value we're going to pass is the address of the
+                thing we just pushed.  */
+             /*args[i] = value_from_longest (lookup_pointer_type (value_type),
+               (LONGEST) addr); */
+             args[i] = value_from_pointer (lookup_pointer_type (arg_type),
+                                           addr);
+           }
+       }
+    }
+
+
+  /* Reserve space for the return structure to be written on the
+     stack, if necessary.  Make certain that the value is correctly
+     aligned. */
+
+  if (struct_return)
+    {
+      int len = TYPE_LENGTH (value_type);
+      if (STACK_ALIGN_P ())
+       /* NOTE: cagney/2003-03-22: Should rely on frame align, rather
+           than stack align to force the alignment of the stack.  */
+       len = STACK_ALIGN (len);
+      if (INNER_THAN (1, 2))
+       {
+         /* Stack grows downward.  Align STRUCT_ADDR and SP after
+             making space for the return value.  */
+         sp -= len;
+         if (gdbarch_frame_align_p (current_gdbarch))
+           sp = gdbarch_frame_align (current_gdbarch, sp);
+         struct_addr = sp;
+       }
+      else
+       {
+         /* Stack grows upward.  Align the frame, allocate space, and
+             then again, re-align the frame??? */
+         if (gdbarch_frame_align_p (current_gdbarch))
+           sp = gdbarch_frame_align (current_gdbarch, sp);
+         struct_addr = sp;
+         sp += len;
+         if (gdbarch_frame_align_p (current_gdbarch))
+           sp = gdbarch_frame_align (current_gdbarch, sp);
+       }
+    }
+
+  /* elz: on HPPA no need for this extra alignment, maybe it is needed
+     on other architectures. This is because all the alignment is
+     taken care of in the above code (ifdef REG_STRUCT_HAS_ADDR) and
+     in hppa_push_arguments */
+  /* NOTE: cagney/2003-03-24: The below code is very broken.  Given an
+     odd sized parameter the below will mis-align the stack.  As was
+     suggested back in '96, better to let PUSH_ARGUMENTS handle it.  */
+  if (DEPRECATED_EXTRA_STACK_ALIGNMENT_NEEDED)
+    {
+      /* MVS 11/22/96: I think at least some of this stack_align code
+        is really broken.  Better to let push_dummy_call() adjust the
+        stack in a target-defined manner.  */
+      if (STACK_ALIGN_P () && INNER_THAN (1, 2))
+       {
+         /* If stack grows down, we must leave a hole at the top. */
+         int len = 0;
+         int i;
+         for (i = nargs - 1; i >= 0; i--)
+           len += TYPE_LENGTH (VALUE_ENCLOSING_TYPE (args[i]));
+         if (DEPRECATED_CALL_DUMMY_STACK_ADJUST_P ())
+           len += DEPRECATED_CALL_DUMMY_STACK_ADJUST;
+         sp -= STACK_ALIGN (len) - len;
+       }
+    }
+
+  /* Create the dummy stack frame.  Pass in the call dummy address as,
+     presumably, the ABI code knows where, in the call dummy, the
+     return address should be pointed.  */
+  if (gdbarch_push_dummy_call_p (current_gdbarch))
+    /* When there is no push_dummy_call method, should this code
+       simply error out.  That would the implementation of this method
+       for all ABIs (which is probably a good thing).  */
+    sp = gdbarch_push_dummy_call (current_gdbarch, current_regcache,
+                                 dummy_addr, nargs, args, sp, struct_return,
+                                 struct_addr);
+  else  if (DEPRECATED_PUSH_ARGUMENTS_P ())
+    /* Keep old targets working.  */
+    sp = DEPRECATED_PUSH_ARGUMENTS (nargs, args, sp, struct_return,
+                                   struct_addr);
+  else
+    sp = legacy_push_arguments (nargs, args, sp, struct_return, struct_addr);
+
+  if (DEPRECATED_PUSH_RETURN_ADDRESS_P ())
+    /* for targets that use no CALL_DUMMY */
+    /* There are a number of targets now which actually don't write
+       any CALL_DUMMY instructions into the target, but instead just
+       save the machine state, push the arguments, and jump directly
+       to the callee function.  Since this doesn't actually involve
+       executing a JSR/BSR instruction, the return address must be set
+       up by hand, either by pushing onto the stack or copying into a
+       return-address register as appropriate.  Formerly this has been
+       done in PUSH_ARGUMENTS, but that's overloading its
+       functionality a bit, so I'm making it explicit to do it here.  */
+    /* NOTE: cagney/2003-04-22: The first parameter ("real_pc") has
+       been replaced with zero, it turns out that no implementation
+       used that parameter.  This occured because the value being
+       supplied - the address of the called function's entry point
+       instead of the address of the breakpoint that the called
+       function should return to - wasn't useful.  */
+    sp = DEPRECATED_PUSH_RETURN_ADDRESS (0, sp);
+
+  /* NOTE: cagney/2003-03-23: Diable this code when there is a
+     push_dummy_call() method.  Since that method will have already
+     handled any alignment issues, the code below is entirely
+     redundant.  */
+  if (!gdbarch_push_dummy_call_p (current_gdbarch)
+      && STACK_ALIGN_P () && !INNER_THAN (1, 2))
+    {
+      /* If stack grows up, we must leave a hole at the bottom, note
+         that sp already has been advanced for the arguments!  */
+      if (DEPRECATED_CALL_DUMMY_STACK_ADJUST_P ())
+       sp += DEPRECATED_CALL_DUMMY_STACK_ADJUST;
+      sp = STACK_ALIGN (sp);
+    }
+
+/* XXX This seems wrong.  For stacks that grow down we shouldn't do
+   anything here!  */
+  /* MVS 11/22/96: I think at least some of this stack_align code is
+     really broken.  Better to let PUSH_ARGUMENTS adjust the stack in
+     a target-defined manner.  */
+  if (DEPRECATED_CALL_DUMMY_STACK_ADJUST_P ())
+    if (INNER_THAN (1, 2))
+      {
+       /* stack grows downward */
+       sp -= DEPRECATED_CALL_DUMMY_STACK_ADJUST;
+      }
+
+  /* Store the address at which the structure is supposed to be
+     written.  */
+  /* NOTE: 2003-03-24: Since PUSH_ARGUMENTS can (and typically does)
+     store the struct return address, this call is entirely redundant.  */
+  if (struct_return && DEPRECATED_STORE_STRUCT_RETURN_P ())
+    DEPRECATED_STORE_STRUCT_RETURN (struct_addr, sp);
+
+  /* Write the stack pointer.  This is here because the statements above
+     might fool with it.  On SPARC, this write also stores the register
+     window into the right place in the new stack frame, which otherwise
+     wouldn't happen.  (See store_inferior_registers in sparc-nat.c.)  */
+  /* NOTE: cagney/2003-03-23: Disable this code when there is a
+     push_dummy_call() method.  Since that method will have already
+     stored the stack pointer (as part of creating the fake call
+     frame), and none of the code following that code adjusts the
+     stack-pointer value, the below call is entirely redundant.  */
+  if (DEPRECATED_DUMMY_WRITE_SP_P ())
+    DEPRECATED_DUMMY_WRITE_SP (sp);
+
+  if (SAVE_DUMMY_FRAME_TOS_P ())
+    SAVE_DUMMY_FRAME_TOS (sp);
+
+  /* Now proceed, having reached the desired place.  */
+  clear_proceed_status ();
+    
+  /* Create a momentary breakpoint at the return address of the
+     inferior.  That way it breaks when it returns.  */
+
+  {
+    struct breakpoint *bpt;
+    struct symtab_and_line sal;
+    struct frame_id frame;
+    init_sal (&sal);           /* initialize to zeroes */
+    sal.pc = bp_addr;
+    sal.section = find_pc_overlay (sal.pc);
+    /* Set up a frame ID for the dummy frame so we can pass it to
+       set_momentary_breakpoint.  We need to give the breakpoint a
+       frame ID so that the breakpoint code can correctly re-identify
+       the dummy breakpoint.  */
+    /* The assumption here is that push_dummy_call() returned the
+       stack part of the frame ID.  Unfortunatly, many older
+       architectures were, via a convoluted mess, relying on the
+       poorly defined and greatly overloaded DEPRECATED_TARGET_READ_FP
+       or DEPRECATED_FP_REGNUM to supply the value.  */
+    if (DEPRECATED_TARGET_READ_FP_P ())
+      frame = frame_id_build (DEPRECATED_TARGET_READ_FP (), sal.pc);
+    else if (DEPRECATED_FP_REGNUM >= 0)
+      frame = frame_id_build (read_register (DEPRECATED_FP_REGNUM), sal.pc);
+    else
+      frame = frame_id_build (sp, sal.pc);
+    bpt = set_momentary_breakpoint (sal, frame, bp_call_dummy);
+    bpt->disposition = disp_del;
+  }
+
+  /* Execute a "stack dummy", a piece of code stored in the stack by
+     the debugger to be executed in the inferior.
+
+     The dummy's frame is automatically popped whenever that break is
+     hit.  If that is the first time the program stops,
+     call_function_by_hand returns to its caller with that frame
+     already gone and sets RC to 0.
+   
+     Otherwise, set RC to a non-zero value.  If the called function
+     receives a random signal, we do not allow the user to continue
+     executing it as this may not work.  The dummy frame is poped and
+     we return 1.  If we hit a breakpoint, we leave the frame in place
+     and return 2 (the frame will eventually be popped when we do hit
+     the dummy end breakpoint).  */
+
+  {
+    struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0);
+    int saved_async = 0;
+
+    /* If all error()s out of proceed ended up calling normal_stop
+       (and perhaps they should; it already does in the special case
+       of error out of resume()), then we wouldn't need this.  */
+    make_cleanup (breakpoint_auto_delete_contents, &stop_bpstat);
+
+    disable_watchpoints_before_interactive_call_start ();
+    proceed_to_finish = 1;     /* We want stop_registers, please... */
+
+    if (target_can_async_p ())
+      saved_async = target_async_mask (0);
+    
+    proceed (real_pc, TARGET_SIGNAL_0, 0);
+    
+    if (saved_async)
+      target_async_mask (saved_async);
+    
+    enable_watchpoints_after_interactive_call_stop ();
+      
+    discard_cleanups (old_cleanups);
+  }
+
+  if (stopped_by_random_signal || !stop_stack_dummy)
+    {
+      /* Find the name of the function we're about to complain about.  */
+      char *name = NULL;
+      {
+       struct symbol *symbol = find_pc_function (funaddr);
+       if (symbol)
+         name = SYMBOL_PRINT_NAME (symbol);
+       else
+         {
+           /* Try the minimal symbols.  */
+           struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr);
+           if (msymbol)
+             name = SYMBOL_PRINT_NAME (msymbol);
+         }
+      }
+      if (name == NULL)
+       {
+         /* NOTE: cagney/2003-04-23: Don't blame me.  This code dates
+             back to 1993-07-08, I simply moved it.  */
+         char format[80];
+         sprintf (format, "at %s", local_hex_format ());
+         name = alloca (80);
+         /* FIXME-32x64: assumes funaddr fits in a long.  */
+         sprintf (name, format, (unsigned long) funaddr);
+       }
+      if (stopped_by_random_signal)
+       {
+         /* We stopped inside the FUNCTION because of a random
+            signal.  Further execution of the FUNCTION is not
+            allowed. */
+
+         if (unwind_on_signal_p)
+           {
+             /* The user wants the context restored. */
+
+             /* We must get back to the frame we were before the
+                dummy call. */
+             frame_pop (get_current_frame ());
+
+             /* FIXME: Insert a bunch of wrap_here; name can be very
+                long if it's a C++ name with arguments and stuff.  */
+             error ("\
+The program being debugged was signaled while in a function called from GDB.\n\
+GDB has restored the context to what it was before the call.\n\
+To change this behavior use \"set unwindonsignal off\"\n\
+Evaluation of the expression containing the function (%s) will be abandoned.",
+                    name);
+           }
+         else
+           {
+             /* The user wants to stay in the frame where we stopped
+                 (default).*/
+             /* If we restored the inferior status (via the cleanup),
+                we would print a spurious error message (Unable to
+                restore previously selected frame), would write the
+                registers from the inf_status (which is wrong), and
+                would do other wrong things.  */
+             discard_cleanups (inf_status_cleanup);
+             discard_inferior_status (inf_status);
+             /* FIXME: Insert a bunch of wrap_here; name can be very
+                long if it's a C++ name with arguments and stuff.  */
+             error ("\
+The program being debugged was signaled while in a function called from GDB.\n\
+GDB remains in the frame where the signal was received.\n\
+To change this behavior use \"set unwindonsignal on\"\n\
+Evaluation of the expression containing the function (%s) will be abandoned.",
+                    name);
+           }
+       }
+
+      if (!stop_stack_dummy)
+       {
+         /* We hit a breakpoint inside the FUNCTION. */
+         /* If we restored the inferior status (via the cleanup), we
+            would print a spurious error message (Unable to restore
+            previously selected frame), would write the registers
+            from the inf_status (which is wrong), and would do other
+            wrong things.  */
+         discard_cleanups (inf_status_cleanup);
+         discard_inferior_status (inf_status);
+         /* The following error message used to say "The expression
+            which contained the function call has been discarded."
+            It is a hard concept to explain in a few words.  Ideally,
+            GDB would be able to resume evaluation of the expression
+            when the function finally is done executing.  Perhaps
+            someday this will be implemented (it would not be easy).  */
+         /* FIXME: Insert a bunch of wrap_here; name can be very long if it's
+            a C++ name with arguments and stuff.  */
+         error ("\
+The program being debugged stopped while in a function called from GDB.\n\
+When the function (%s) is done executing, GDB will silently\n\
+stop (instead of continuing to evaluate the expression containing\n\
+the function call).", name);
+       }
+
+      /* The above code errors out, so ...  */
+      internal_error (__FILE__, __LINE__, "... should not be here");
+    }
+
+  /* If we get here the called FUNCTION run to completion. */
+
+  /* On normal return, the stack dummy has been popped already.  */
+  regcache_cpy_no_passthrough (retbuf, stop_registers);
+
+  /* Restore the inferior status, via its cleanup.  At this stage,
+     leave the RETBUF alone.  */
+  do_cleanups (inf_status_cleanup);
+
+  /* Figure out the value returned by the function.  */
+  /* elz: I defined this new macro for the hppa architecture only.
+     this gives us a way to get the value returned by the function
+     from the stack, at the same address we told the function to put
+     it.  We cannot assume on the pa that r28 still contains the
+     address of the returned structure. Usually this will be
+     overwritten by the callee.  I don't know about other
+     architectures, so I defined this macro */
+#ifdef VALUE_RETURNED_FROM_STACK
+  if (struct_return)
+    {
+      do_cleanups (retbuf_cleanup);
+      return VALUE_RETURNED_FROM_STACK (value_type, struct_addr);
+    }
+#endif
+  /* NOTE: cagney/2002-09-10: Only when the stack has been correctly
+     aligned (using frame_align()) do we can trust STRUCT_ADDR and
+     fetch the return value direct from the stack.  This lack of trust
+     comes about because legacy targets have a nasty habit of
+     silently, and local to PUSH_ARGUMENTS(), moving STRUCT_ADDR.  For
+     such targets, just hope that value_being_returned() can find the
+     adjusted value.  */
+  if (struct_return && gdbarch_frame_align_p (current_gdbarch))
+    {
+      struct value *retval = value_at (value_type, struct_addr, NULL);
+      do_cleanups (retbuf_cleanup);
+      return retval;
+    }
+  else
+    {
+      struct value *retval = value_being_returned (value_type, retbuf,
+                                                  struct_return);
+      do_cleanups (retbuf_cleanup);
+      return retval;
+    }
+}
+
+void _initialize_infcall (void);
+
+void
+_initialize_infcall (void)
+{
+  add_setshow_boolean_cmd ("coerce-float-to-double", class_obscure,
+                          &coerce_float_to_double_p, "\
+Set coercion of floats to doubles when calling functions\n\
+Variables of type float should generally be converted to doubles before\n\
+calling an unprototyped function, and left alone when calling a prototyped\n\
+function.  However, some older debug info formats do not provide enough\n\
+information to determine that a function is prototyped.  If this flag is\n\
+set, GDB will perform the conversion for a function it considers\n\
+unprototyped.\n\
+The default is to perform the conversion.\n", "\
+Show coercion of floats to doubles when calling functions\n\
+Variables of type float should generally be converted to doubles before\n\
+calling an unprototyped function, and left alone when calling a prototyped\n\
+function.  However, some older debug info formats do not provide enough\n\
+information to determine that a function is prototyped.  If this flag is\n\
+set, GDB will perform the conversion for a function it considers\n\
+unprototyped.\n\
+The default is to perform the conversion.\n",
+                          NULL, NULL, &setlist, &showlist);
+
+  add_setshow_boolean_cmd ("unwindonsignal", no_class,
+                          &unwind_on_signal_p, "\
+Set unwinding of stack if a signal is received while in a call dummy.\n\
+The unwindonsignal lets the user determine what gdb should do if a signal\n\
+is received while in a function called from gdb (call dummy).  If set, gdb\n\
+unwinds the stack and restore the context to what as it was before the call.\n\
+The default is to stop in the frame where the signal was received.", "\
+Set unwinding of stack if a signal is received while in a call dummy.\n\
+The unwindonsignal lets the user determine what gdb should do if a signal\n\
+is received while in a function called from gdb (call dummy).  If set, gdb\n\
+unwinds the stack and restore the context to what as it was before the call.\n\
+The default is to stop in the frame where the signal was received.",
+                          NULL, NULL, &setlist, &showlist);
+}
diff --git a/gdb/infcall.h b/gdb/infcall.h
new file mode 100644 (file)
index 0000000..05d06e0
--- /dev/null
@@ -0,0 +1,43 @@
+/* Perform an inferior function call, for GDB, the GNU debugger.
+
+   Copyright 2003 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
+   (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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef INFCALL_H
+#define INFCALL_H
+
+struct value;
+struct type;
+
+extern CORE_ADDR find_function_addr (struct value *function, 
+                                    struct type **retval_type);
+
+/* Perform a function call in the inferior.
+
+   ARGS is a vector of values of arguments (NARGS of them).  FUNCTION
+   is a value, the function to be called.  Returns a value
+   representing what the function returned.  May fail to return, if a
+   breakpoint or signal is hit during the execution of the function.
+
+   ARGS is modified to contain coerced values. */
+
+extern struct value *call_function_by_hand (struct value *function, int nargs,
+                                           struct value **args);
+
+#endif
diff --git a/libiberty/snprintf.c b/libiberty/snprintf.c
new file mode 100644 (file)
index 0000000..8916469
--- /dev/null
@@ -0,0 +1,65 @@
+/* Implement the snprintf function.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>.
+
+This file is part of the libiberty library.  This library 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, or (at your option)
+any later version.
+
+This library 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+As a special exception, if you link this library with files
+compiled with a GNU compiler to produce an executable, this does not cause
+the resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why
+the executable file might be covered by the GNU General Public License. */
+
+/*
+
+@deftypefn Supplemental int snprintf (char *@var{buf}, size_t @var{n}, const char *@var{format}, ...)
+
+This function is similar to sprintf, but it will print at most @var{n}
+characters.  On error the return value is -1, otherwise it returns the
+number of characters that would have been printed had @var{n} been
+sufficiently large, regardless of the actual value of @var{n}.  Note
+some pre-C99 system libraries do not implement this correctly so users
+cannot generally rely on the return value if the system version of
+this function is used.
+
+@end deftypefn
+
+*/
+
+#include "ansidecl.h"
+
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#include <stddef.h>
+#else
+#include <varargs.h>
+#define size_t unsigned long
+#endif
+
+int vsnprintf PARAMS ((char *, size_t, const char *, va_list));
+
+int
+snprintf VPARAMS ((char *s, size_t n, const char *format, ...))
+{
+  int result;
+  VA_OPEN (ap, format);
+  VA_FIXEDARG (ap, char *, s);
+  VA_FIXEDARG (ap, size_t, n);
+  VA_FIXEDARG (ap, const char *, format);
+  result = vsnprintf (s, n, format, ap);
+  VA_CLOSE (ap);
+  return result;
+}
diff --git a/libiberty/vsnprintf.c b/libiberty/vsnprintf.c
new file mode 100644 (file)
index 0000000..fd3dd18
--- /dev/null
@@ -0,0 +1,153 @@
+/* Implement the vsnprintf function.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>.
+
+This file is part of the libiberty library.  This library 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, or (at your option)
+any later version.
+
+This library 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+As a special exception, if you link this library with files
+compiled with a GNU compiler to produce an executable, this does not cause
+the resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why
+the executable file might be covered by the GNU General Public License. */
+
+/*
+
+@deftypefn Supplemental int vsnprintf (char *@var{buf}, size_t @var{n}, const char *@var{format}, va_list @var{ap})
+
+This function is similar to vsprintf, but it will print at most
+@var{n} characters.  On error the return value is -1, otherwise it
+returns the number of characters that would have been printed had
+@var{n} been sufficiently large, regardless of the actual value of
+@var{n}.  Note some pre-C99 system libraries do not implement this
+correctly so users cannot generally rely on the return value if the
+system version of this function is used.
+
+@end deftypefn
+
+*/
+
+#include "config.h"
+#include "ansidecl.h"
+
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "libiberty.h"
+
+/* This implementation relies on a working vasprintf.  */
+int
+vsnprintf (s, n, format, ap)
+     char * s;
+     size_t n;
+     const char *format;
+     va_list ap;
+{
+  char *buf = 0;
+  int result = vasprintf (&buf, format, ap);
+
+  if (!buf)
+    return -1;
+  if (result < 0)
+    {
+      free (buf);
+      return -1;
+    }
+
+  result = strlen (buf);
+  if (n > 0)
+    {
+      if ((long) n > result)
+       memcpy (s, buf, result+1);
+      else
+        {
+         memcpy (s, buf, n-1);
+         s[n - 1] = 0;
+       }
+    }
+  free (buf);
+  return result;
+}
+
+#ifdef TEST
+/* Set the buffer to a known state.  */
+#define CLEAR(BUF) do { memset ((BUF), 'X', sizeof (BUF)); (BUF)[14] = '\0'; } while (0)
+/* For assertions.  */
+#define VERIFY(P) do { if (!(P)) abort(); } while (0)
+
+static int ATTRIBUTE_PRINTF_3
+checkit VPARAMS ((char *s, size_t n, const char *format, ...))
+{
+  int result;
+  VA_OPEN (ap, format);
+  VA_FIXEDARG (ap, char *, s);
+  VA_FIXEDARG (ap, size_t, n);
+  VA_FIXEDARG (ap, const char *, format);
+  result = vsnprintf (s, n, format, ap);
+  VA_CLOSE (ap);
+  return result;
+}
+
+extern int main PARAMS ((void));
+int
+main ()
+{
+  char buf[128];
+  int status;
+  
+  CLEAR (buf);
+  status = checkit (buf, 10, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && memcmp (buf, "foobar:9\0XXXXX\0", 15) == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 9, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && memcmp (buf, "foobar:9\0XXXXX\0", 15) == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 8, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && memcmp (buf, "foobar:\0XXXXXX\0", 15) == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 7, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && memcmp (buf, "foobar\0XXXXXXX\0", 15) == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 6, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && memcmp (buf, "fooba\0XXXXXXXX\0", 15) == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 2, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && memcmp (buf, "f\0XXXXXXXXXXXX\0", 15) == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 1, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && memcmp (buf, "\0XXXXXXXXXXXXX\0", 15) == 0);
+
+  CLEAR (buf);
+  status = checkit (buf, 0, "%s:%d", "foobar", 9);
+  VERIFY (status==8 && memcmp (buf, "XXXXXXXXXXXXXX\0", 15) == 0);
+
+  return 0;
+}
+#endif /* TEST */