diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-10-04 03:08:50 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-10-04 03:08:50 +0000 |
commit | 8a4e67633c41ee9aecfd049e2a591100d1c89799 (patch) | |
tree | 670b15daaad2d99fa60833fe8b45cc2f759a4318 /gcc/config/ia64/fde-glibc.c | |
parent | 583cfadbc63667ff01e755c932100be156c81a23 (diff) | |
download | gcc-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.c | 141 |
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; +} |