summaryrefslogtreecommitdiff
path: root/gcc/config/ia64/fde-glibc.c
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2000-10-04 03:08:50 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2000-10-04 03:08:50 +0000
commit8a4e67633c41ee9aecfd049e2a591100d1c89799 (patch)
tree670b15daaad2d99fa60833fe8b45cc2f759a4318 /gcc/config/ia64/fde-glibc.c
parent583cfadbc63667ff01e755c932100be156c81a23 (diff)
downloadgcc-8a4e67633c41ee9aecfd049e2a591100d1c89799.tar.gz
* configure.in (ia64-linux) [tmake_file]: Add ia64/t-glibc.
* config/ia64/crtbegin.asm (__EH_FRAME_BEGIN__): Remove. (segrel_ofs): Remove. (__ia64_app_header): New. (frame_object): Remove. (.init): Set __ia64_app_header when non-shared. (__do_global_dtors_aux): Do not call __deregister_frame_info. (__do_frame_setup): Remove. * config/ia64/crtend.asm (__EH_FRAME_END__): Remove. (__do_frame_setup_aux): Remove. * config/ia64/frame-ia64.c (object_mutex): Remove. (bad_record): Remove. (init_object_mutex): Remove. (init_object_mutex_once): Remove. (fde_compare): Remove. (__register_frame_info_aux): Remove. (frame_init): Remove. (find_fde): Remove. (*): Use ISO function definitions. (P3_record_types): Constify. (P7_record_types, P7_additional_fields): Constify. (P8_record_types, P8_additional_fields): Constify. (read_P_record): Remove parenthesis warning. Use structure assignment instead of memcpy. (execute_one_ia64_descriptor): Likewise. (__build_ia64_frame_state): Use __ia64_find_fde. (record_name, print_record, print_all_records): Remove. * config/ia64/frame-ia64.h: New file. * config/ia64/fde-glibc.c: New file. * config/ia64/t-glibc: New file. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@36705 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/ia64/fde-glibc.c')
-rw-r--r--gcc/config/ia64/fde-glibc.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/gcc/config/ia64/fde-glibc.c b/gcc/config/ia64/fde-glibc.c
new file mode 100644
index 00000000000..09484956205
--- /dev/null
+++ b/gcc/config/ia64/fde-glibc.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ Contributed by Richard Henderson <rth@cygnus.com>.
+
+ This file is part of GNU CC.
+
+ GNU CC 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.
+
+ GNU CC 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 other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself 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. */
+
+/* Locate the FDE entry for a given address, using glibc ld.so routines
+ to avoid register/deregister calls at DSO load/unload. */
+
+#include <stdlib.h>
+#include <link.h>
+#include <bits/libc-lock.h>
+#include "frame-ia64.h"
+
+
+/* Initialized by crtbegin from the main application. */
+extern Elf64_Ehdr *__ia64_app_header;
+
+/* ??? A redeclaration of the lock in ld.so. Perhaps this should
+ appear in <link.h> in a new glibc version. */
+__libc_lock_define (extern, _dl_load_lock)
+
+/* ??? _dl_load_lock is not exported from glibc 2.1, but it is
+ from glibc 2.2. Remove this when folks have migrated. */
+#pragma weak _dl_load_lock
+
+/* This always exists, even in a static application. */
+extern struct link_map *_dl_loaded;
+
+static fde *
+find_fde_for_dso (Elf64_Addr pc, Elf64_Ehdr *ehdr)
+{
+ Elf64_Phdr *phdr, *p_unwind;
+ long n, match;
+ Elf64_Addr load_base, seg_base;
+ fde *f;
+
+ /* Verify that we are looking at an ELF header. */
+ if (ehdr->e_ident[0] != 0x7f
+ || ehdr->e_ident[1] != 'E'
+ || ehdr->e_ident[2] != 'L'
+ || ehdr->e_ident[3] != 'F'
+ || ehdr->e_ident[EI_CLASS] != ELFCLASS64
+ || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
+ || ehdr->e_machine != EM_IA_64)
+ abort ();
+
+ match = 0;
+ phdr = (Elf64_Phdr *)((char *)ehdr + ehdr->e_phoff);
+ load_base = (ehdr->e_type == ET_DYN ? (Elf64_Addr)ehdr : 0);
+ p_unwind = NULL;
+
+ /* See if PC falls into one of the loaded segments. Find the unwind
+ segment at the same time. */
+ for (n = ehdr->e_phnum; --n >= 0; phdr++)
+ {
+ if (phdr->p_type == PT_LOAD)
+ {
+ Elf64_Addr vaddr = phdr->p_vaddr + load_base;
+ if (pc >= vaddr && pc < vaddr + phdr->p_memsz)
+ match = 1;
+ }
+ else if (phdr->p_type == PT_IA_64_UNWIND)
+ p_unwind = phdr;
+ }
+ if (!match || !p_unwind)
+ return NULL;
+
+ /* Search for the FDE within the unwind segment. */
+ /* ??? Ideally ld would have sorted this for us by address. Until
+ that's fixed, we must do a linear search. */
+
+ f = (fde *) (p_unwind->p_vaddr + load_base);
+ seg_base = (Elf64_Addr) ehdr;
+ for (n = p_unwind->p_memsz / sizeof (fde); --n >= 0; ++f)
+ if (pc >= f->start_offset + seg_base && pc < f->end_offset + seg_base)
+ return f;
+
+ return NULL;
+}
+
+/* Return a pointer to the FDE for the function containing PC. */
+fde *
+__ia64_find_fde (void *pc, void **pc_base)
+{
+ fde *ret;
+ struct link_map *map;
+
+ /* Check the main application first, hoping that most of the user's
+ code is there instead of in some library. */
+ ret = find_fde_for_dso ((Elf64_Addr)pc, __ia64_app_header);
+ if (ret)
+ {
+ *pc_base = __ia64_app_header;
+ return ret;
+ }
+
+ /* Glibc is probably unique in that we can (with certain restrictions)
+ dynamicly load libraries into staticly linked applications. Thus
+ we _always_ check _dl_loaded. */
+
+ if (&_dl_load_lock)
+ __libc_lock_lock (_dl_load_lock);
+
+ for (map = _dl_loaded; map ; map = map->l_next)
+ {
+ /* Skip the main application's entry. */
+ if (map->l_name[0] == 0)
+ continue;
+ ret = find_fde_for_dso ((Elf64_Addr)pc, (Elf64_Ehdr *)map->l_addr);
+ if (ret)
+ break;
+ }
+
+ if (&_dl_load_lock)
+ __libc_lock_unlock (_dl_load_lock);
+
+ *pc_base = (void *)(map ? map->l_addr : 0);
+ return ret;
+}