aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobody <>2003-04-30 01:27:54 +0000
committernobody <>2003-04-30 01:27:54 +0000
commitef7983a6fb75b76eeefc985620624b9247f4e1fa (patch)
treee25313c6d809a807fb026eae56adee1907596e1c
parent78f35437dacc7d2a1f88341a70098f1ce5299d05 (diff)
downloadgdb-ef7983a6fb75b76eeefc985620624b9247f4e1fa.zip
gdb-ef7983a6fb75b76eeefc985620624b9247f4e1fa.tar.gz
gdb-ef7983a6fb75b76eeefc985620624b9247f4e1fa.tar.bz2
This commit was manufactured by cvs2svn to create branch
'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
-rw-r--r--bfd/elf32-m68hc1x.c1508
-rw-r--r--bfd/elf32-m68hc1x.h205
-rwxr-xr-xgdb/gdb_gcore.sh81
-rw-r--r--gdb/infcall.c981
-rw-r--r--gdb/infcall.h43
-rw-r--r--libiberty/snprintf.c65
-rw-r--r--libiberty/vsnprintf.c153
7 files changed, 3036 insertions, 0 deletions
diff --git a/bfd/elf32-m68hc1x.c b/bfd/elf32-m68hc1x.c
new file mode 100644
index 0000000..0696a36
--- /dev/null
+++ b/bfd/elf32-m68hc1x.c
@@ -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;
+}
+
+
+
+/* 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
index 0000000..e70c172
--- /dev/null
+++ b/bfd/elf32-m68hc1x.h
@@ -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
index 0000000..9b42808
--- /dev/null
+++ b/gdb/gdb_gcore.sh
@@ -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
index 0000000..1ce22fb
--- /dev/null
+++ b/gdb/infcall.c
@@ -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
index 0000000..05d06e0
--- /dev/null
+++ b/gdb/infcall.h
@@ -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
index 0000000..8916469
--- /dev/null
+++ b/libiberty/snprintf.c
@@ -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
index 0000000..fd3dd18
--- /dev/null
+++ b/libiberty/vsnprintf.c
@@ -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 */