Back to index

glibc  2.9
Classes | Defines | Functions
unwind-dw2-fde-glibc.c File Reference
#include <link.h>
#include <stddef.h>
#include <unwind-dw2-fde.c>

Go to the source code of this file.

Classes

struct  unw_eh_callback_data
struct  unw_eh_frame_hdr

Defines

#define _Unwind_Find_FDE   _Unwind_Find_registered_FDE

Functions

fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases *bases)
fde * _Unwind_Find_FDE (void *, struct dwarf_eh_bases *)
static _Unwind_Ptr base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data)
static int _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)

Class Documentation

struct unw_eh_callback_data

Definition at line 22 of file find_exidx.c.

Class Members
void * dbase
int exidx_len
_Unwind_Ptr exidx_start
void * func
_Unwind_Ptr pc
fde * ret
void * tbase
struct unw_eh_frame_hdr

Definition at line 53 of file unwind-dw2-fde-glibc.c.

Class Members
unsigned char eh_frame_ptr_enc
unsigned char fde_count_enc
unsigned char table_enc
unsigned char version

Define Documentation

Definition at line 34 of file unwind-dw2-fde-glibc.c.


Function Documentation

fde* _Unwind_Find_FDE ( void *  pc,
struct dwarf_eh_bases bases 
)

Definition at line 77 of file unwind-dw2-fde-glibc.c.

{
  abort ();
}
fde* _Unwind_Find_registered_FDE ( void *  pc,
struct dwarf_eh_bases bases 
)
static int _Unwind_IteratePhdrCallback ( struct dl_phdr_info *  info,
size_t  size,
void *  ptr 
) [static]

Definition at line 86 of file unwind-dw2-fde-glibc.c.

{
  struct unw_eh_callback_data *data = (struct unw_eh_callback_data *) ptr;
  const ElfW(Phdr) *phdr, *p_eh_frame_hdr, *p_dynamic;
  long n, match;
  _Unwind_Ptr load_base;
  const unsigned char *p;
  const struct unw_eh_frame_hdr *hdr;
  _Unwind_Ptr eh_frame;
  struct object ob;

  /* 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_eh_frame_hdr = NULL;
  p_dynamic = NULL;

  /* See if PC falls into one of the loaded segments.  Find the eh_frame
     segment at the same time.  */
  for (n = info->dlpi_phnum; --n >= 0; phdr++)
    {
      if (phdr->p_type == PT_LOAD)
       {
         _Unwind_Ptr vaddr = phdr->p_vaddr + load_base;
         if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
           match = 1;
       }
      else if (phdr->p_type == PT_GNU_EH_FRAME)
       p_eh_frame_hdr = phdr;
      else if (phdr->p_type == PT_DYNAMIC)
       p_dynamic = phdr;
    }
  if (!match || !p_eh_frame_hdr)
    return 0;

  /* Read .eh_frame_hdr header.  */
  hdr = (const struct unw_eh_frame_hdr *)
       (p_eh_frame_hdr->p_vaddr + load_base);
  if (hdr->version != 1)
    return 1;

#ifdef CRT_GET_RFIB_DATA
# ifdef __i386__
  data->dbase = NULL;
  if (p_dynamic)
    {
      /* For dynamicly linked executables and shared libraries,
        DT_PLTGOT is the gp value for that object.  */
      ElfW(Dyn) *dyn = (ElfW(Dyn) *)(p_dynamic->p_vaddr + load_base);
      for (; dyn->d_tag != DT_NULL ; dyn++)
       if (dyn->d_tag == DT_PLTGOT)
         {
           /* On IA-32, _DYNAMIC is writable and GLIBC has relocated it.  */
           data->dbase = (void *) dyn->d_un.d_ptr;
           break;
         }
    }
# else
#  error What is DW_EH_PE_datarel base on this platform?
# endif
#endif
#ifdef CRT_GET_RFIB_TEXT
# error What is DW_EH_PE_textrel base on this platform?
#endif

  p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
                                base_from_cb_data (hdr->eh_frame_ptr_enc,
                                                 data),
                                (const unsigned char *) (hdr + 1),
                                &eh_frame);

  /* We require here specific table encoding to speed things up.
     Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start
     as base, not the processor specific DW_EH_PE_datarel.  */
  if (hdr->fde_count_enc != DW_EH_PE_omit
      && hdr->table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4))
    {
      _Unwind_Ptr fde_count;

      p = read_encoded_value_with_base (hdr->fde_count_enc,
                                   base_from_cb_data (hdr->fde_count_enc,
                                                    data),
                                   p, &fde_count);
      /* Shouldn't happen.  */
      if (fde_count == 0)
       return 1;
      if ((((_Unwind_Ptr) p) & 3) == 0)
       {
         struct fde_table {
           signed initial_loc __attribute__ ((mode (SI)));
           signed fde __attribute__ ((mode (SI)));
         };
         const struct fde_table *table = (const struct fde_table *) p;
         size_t lo, hi, mid;
         _Unwind_Ptr data_base = (_Unwind_Ptr) hdr;
         fde *f;
         unsigned int f_enc, f_enc_size;
         _Unwind_Ptr range;

         mid = fde_count - 1;
         if (data->pc < table[0].initial_loc + data_base)
           return 1;
         else if (data->pc < table[mid].initial_loc + data_base)
           {
             lo = 0;
             hi = mid;

             while (lo < hi)
              {
                mid = (lo + hi) / 2;
                if (data->pc < table[mid].initial_loc + data_base)
                  hi = mid;
                else if (data->pc >= table[mid + 1].initial_loc + data_base)
                  lo = mid + 1;
                else
                  break;
              }

             if (lo >= hi)
              __gxx_abort ();
           }

         f = (fde *) (table[mid].fde + data_base);
         f_enc = get_fde_encoding (f);
         f_enc_size = size_of_encoded_value (f_enc);
         read_encoded_value_with_base (f_enc & 0x0f, 0,
                                   &f->pc_begin[f_enc_size], &range);
         if (data->pc < table[mid].initial_loc + data_base + range)
           data->ret = f;
         data->func = (void *) (table[mid].initial_loc + data_base);
         return 1;
       }
    }

  /* We have no sorted search table, so need to go the slow way.
     As soon as GLIBC will provide API so to notify that a library has been
     removed, we could cache this (and thus use search_object).  */
  ob.pc_begin = NULL;
  ob.tbase = data->tbase;
  ob.dbase = data->dbase;
  ob.u.single = (fde *) eh_frame;
  ob.s.i = 0;
  ob.s.b.mixed_encoding = 1;  /* Need to assume worst case.  */
  data->ret = linear_search_fdes (&ob, (fde *) eh_frame, (void *) data->pc);
  if (data->ret != NULL)
    {
      unsigned int encoding = get_fde_encoding (data->ret);
      _Unwind_Ptr func;
      read_encoded_value_with_base (encoding,
                                base_from_cb_data (encoding, data),
                                data->ret->pc_begin, &func);
      data->func = (void *) func;
    }
  return 1;
}

Here is the call graph for this function:

static _Unwind_Ptr base_from_cb_data ( unsigned char  encoding,
struct unw_eh_callback_data data 
) [static]

Definition at line 65 of file unwind-dw2-fde-glibc.c.

{
  if (encoding == DW_EH_PE_omit)
    return 0;

  switch (encoding & 0x70)
    {
    case DW_EH_PE_absptr:
    case DW_EH_PE_pcrel:
    case DW_EH_PE_aligned:
      return 0;

    case DW_EH_PE_textrel:
      return (_Unwind_Ptr) data->tbase;
    case DW_EH_PE_datarel:
      return (_Unwind_Ptr) data->dbase;
    }
  abort ();
}

Here is the call graph for this function:

Here is the caller graph for this function: