OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [config/] [ia64/] [fde-glibc.c] - Rev 282

Compare with Previous | Blame | View Log

/* Copyright (C) 2000, 2001, 2003, 2009 Free Software Foundation, Inc.
   Contributed by Richard Henderson <rth@cygnus.com>.
 
   This file is part of GCC.
 
   GCC 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 3, or (at your option)
   any later version.
 
   GCC 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.
 
   Under Section 7 of GPL version 3, you are granted additional
   permissions described in the GCC Runtime Library Exception, version
   3.1, as published by the Free Software Foundation.
 
   You should have received a copy of the GNU General Public License and
   a copy of the GCC Runtime Library Exception along with this program;
   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
   <http://www.gnu.org/licenses/>.  */
 
/* Locate the FDE entry for a given address, using glibc ld.so routines
   to avoid register/deregister calls at DSO load/unload.  */
 
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include "config.h"
#include <stddef.h>
#include <stdlib.h>
#include <link.h>
#include "unwind-ia64.h"
 
#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \
    || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG))
# error You need GLIBC 2.2.4 or later on IA-64 Linux
#endif
 
struct unw_ia64_callback_data
{
  Elf64_Addr pc;
  unsigned long *segment_base;
  unsigned long *gp;
  struct unw_table_entry *ret;
};
 
static int
_Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
{
  struct unw_ia64_callback_data *data = (struct unw_ia64_callback_data *) ptr;
  const Elf64_Phdr *phdr, *p_unwind, *p_dynamic;
  long n, match;
  Elf64_Addr load_base, seg_base;
  struct unw_table_entry *f_base, *f;
  size_t lo, hi;
 
  /* Make sure struct dl_phdr_info is at least as big as we need.  */
  if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
	     + sizeof (info->dlpi_phnum))
    return -1;
 
  match = 0;
  phdr = info->dlpi_phdr;
  load_base = info->dlpi_addr;
  p_unwind = NULL;
  p_dynamic = NULL;
  seg_base = ~(Elf64_Addr) 0;
 
  /* See if PC falls into one of the loaded segments.  Find the unwind
     segment at the same time.  */
  for (n = info->dlpi_phnum; --n >= 0; phdr++)
    {
      if (phdr->p_type == PT_LOAD)
	{
	  Elf64_Addr vaddr = phdr->p_vaddr + load_base;
	  if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
	    match = 1;
	  if (vaddr < seg_base)
	    seg_base = vaddr;
	}
      else if (phdr->p_type == PT_IA_64_UNWIND)
	p_unwind = phdr;
      else if (phdr->p_type == PT_DYNAMIC)
	p_dynamic = phdr;
    }
  if (!match || !p_unwind)
    return 0;
 
  /* Search for the FDE within the unwind segment.  */
 
  f_base = (struct unw_table_entry *) (p_unwind->p_vaddr + load_base);
  lo = 0;
  hi = p_unwind->p_memsz / sizeof (struct unw_table_entry);
 
  while (lo < hi)
    {
      size_t mid = (lo + hi) / 2;
 
      f = f_base + mid;
      if (data->pc < f->start_offset + seg_base)
	hi = mid;
      else if (data->pc >= f->end_offset + seg_base)
	lo = mid + 1;
      else
        goto found;
    }
  /* No need to search for further libraries when we know pc is contained
     in this library.  */
  return 1;
 
 found:
  *data->segment_base = seg_base;
  *data->gp = 0;
  data->ret = f;
 
  if (p_dynamic)
    {
      /* For dynamically linked executables and shared libraries,
	 DT_PLTGOT is the gp value for that object.  */
      Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base);
      for (; dyn->d_tag != DT_NULL ; dyn++)
	if (dyn->d_tag == DT_PLTGOT)
	  {
	    /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it.  */
	    *data->gp = dyn->d_un.d_ptr;
	    break;
	  }
    }
  else
    {
      /* Otherwise this is a static executable with no _DYNAMIC.
	 The gp is constant program-wide.  */
      register unsigned long gp __asm__("gp");
      *data->gp = gp;
    }
 
  return 1;
}
 
/* Return a pointer to the unwind table entry for the function
   containing PC.  */
 
struct unw_table_entry *
_Unwind_FindTableEntry (void *pc, unsigned long *segment_base,
                        unsigned long *gp,
                        struct unw_table_entry *ent ATTRIBUTE_UNUSED)
{
  struct unw_ia64_callback_data data;
 
  data.pc = (Elf64_Addr) pc;
  data.segment_base = segment_base;
  data.gp = gp;
  data.ret = NULL;
 
  if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0)
    return NULL;
 
  return data.ret;
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.