示例#1
0
文件: elf-strtab.c 项目: 0mp/freebsd
struct elf_strtab_hash *
_bfd_elf_strtab_init (void)
{
  struct elf_strtab_hash *table;
  bfd_size_type amt = sizeof (struct elf_strtab_hash);

  table = bfd_malloc (amt);
  if (table == NULL)
    return NULL;

  if (!bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc,
			    sizeof (struct elf_strtab_hash_entry)))
    {
      free (table);
      return NULL;
    }

  table->sec_size = 0;
  table->size = 1;
  table->alloced = 64;
  amt = sizeof (struct elf_strtab_hasn_entry *);
  table->array = bfd_malloc (table->alloced * amt);
  if (table->array == NULL)
    {
      free (table);
      return NULL;
    }

  table->array[0] = NULL;

  return table;
}
/*
 * This function returns a string that describes
 * a section's size, in proper units.
 */
char * pic32_section_size_string (asection *sec)
{
#undef MAX_LEN
#define MAX_LEN 80
#define S1 "size = "
#define S2 " bytes"
#define S3 " PC units"

  char *units;
  char *result = (char *) bfd_malloc (MAX_LEN);

  if (result == (char *) NULL)
    return result;

  if (PIC32_SECTION_IN_DATA_MEMORY(sec) || PIC32_IS_MEMORY_ATTR(sec))
    units = S2;
  else
    units = S3;

  if (sec->rawsize != 0)
    snprintf(result, MAX_LEN, "%s%ld%s", S1, sec->rawsize / 2, units);
  else
    snprintf(result, MAX_LEN, "%s%ld%s", S1, sec->size / 2, units);
    
  return result;
}
char * pic32_section_attr_string (asection *sec)
{
#undef MAX_LEN
#define MAX_LEN 120
#define A1 "attributes = "

  int i,b;
  unsigned int map = pic32_attribute_map(sec);
  char *result = (char *) bfd_malloc (MAX_LEN);

  if (result == (char *) NULL)
    return result;

  result[0] = 0; /* start with a null terminator */
  result = strcat( result, A1 );

  for (i = 0; i < 31; i++) {
    b = map & 1;
    if (b) {
      result = strncat( result, names[i], MAX_LEN - strlen(result) -2);
      result = strcat( result, " " );
    }
    map >>= 1;
  }

  return result;

}
struct m68hc11_cgc_link_hash_table*
m68hc11_cgc_hash_table_create (bfd *abfd)
{
  struct m68hc11_cgc_link_hash_table *ret;
  bfd_size_type amt = sizeof (struct m68hc11_cgc_link_hash_table);

  ret = (struct m68hc11_cgc_link_hash_table *) bfd_zmalloc (amt);
  if (ret == (struct m68hc11_cgc_link_hash_table *) NULL)
    return NULL;

  if (!_bfd_cgc_link_hash_table_init (&ret->root, abfd,
				      _bfd_cgc_link_hash_newfunc,
				      sizeof (struct cgc_link_hash_entry),
				      M68HC11_CGC_DATA))
    {
      free (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)
    {
      free (ret);
      return NULL;
    }
  if (!bfd_hash_table_init (ret->stub_hash_table, stub_hash_newfunc,
			    sizeof (struct cgc32_m68hc11_stub_hash_entry)))
    return NULL;

  return ret;
}
示例#5
0
bfd_boolean
bfd_init_section_compress_status (bfd *abfd, sec_ptr sec)
{
  bfd_size_type uncompressed_size;
  bfd_byte *uncompressed_buffer;
  bfd_boolean ret;

  /* Error if not opened for read.  */
  if (abfd->direction != read_direction
      || sec->size == 0
      || sec->rawsize != 0
      || sec->contents != NULL
      || sec->compress_status != COMPRESS_SECTION_NONE)
    {
      bfd_set_error (bfd_error_invalid_operation);
      return FALSE;
    }

  /* Read in the full section contents and compress it.  */
  uncompressed_size = sec->size;
  uncompressed_buffer = (bfd_byte *) bfd_malloc (uncompressed_size);
  if (!bfd_get_section_contents (abfd, sec, uncompressed_buffer,
				 0, uncompressed_size))
    ret = FALSE;
  else
    {
      uncompressed_size = bfd_compress_section_contents (abfd, sec,
							 uncompressed_buffer,
							 uncompressed_size);
      ret = uncompressed_size != 0;
    }

  return ret;
}
示例#6
0
char *
bfd_get_unique_section_name (bfd *abfd, const char *templat, int *count)
{
  int num;
  unsigned int len;
  char *sname;

  len = strlen (templat);
  sname = (char *) bfd_malloc (len + 8);
  if (sname == NULL)
    return NULL;
  memcpy (sname, templat, len);
  num = 1;
  if (count != NULL)
    num = *count;

  do
    {
      /* If we have a million sections, something is badly wrong.  */
      if (num > 999999)
	abort ();
      sprintf (sname + len, ".%d", num++);
    }
  while (section_hash_lookup (&abfd->section_htab, sname, FALSE, FALSE));

  if (count != NULL)
    *count = num;
  return sname;
}
示例#7
0
	/*******************************************************
		Function: ld_set_section_data

		
	 *******************************************************/
void 
ld_set_section_data(void *pobj,int ndx)
{
    bfd *abfd = (bfd *) pobj;
    Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
    Elf_Internal_Shdr *p_shdr = i_shdrp[ndx];
    size_t size = p_shdr->sh_size;
    char *buf;
    
    if (!size)
    	return;
	
    buf = ((char *) bfd_malloc (size));
    if (buf == NULL) {
    	fprintf(stderr,"bfd_malloc failed in ld_set_section_data for %s\n",abfd->filename);
    	exit(1);
    }

    if (!p_shdr->contents) {
    	if (bfd_seek (	abfd, p_shdr->sh_offset, SEEK_SET) != 0) {
    	    fprintf(stderr,"bfd_seek failed in ld_set_section_data for %s\n",abfd->filename);
    	    exit(1);
	}
	if (bfd_read (	(PTR) buf, 1, size, abfd) != size) {
    	    fprintf(stderr,"Bfd_read failed in ld_set_section_data for %s\n",abfd->filename);
    	    exit(1);
	}
     }
    
    return;

}
示例#8
0
static void *
bfd_arch_i386_onebyte_nop_fill (bfd_size_type count,
				bfd_boolean is_bigendian ATTRIBUTE_UNUSED,
				bfd_boolean code)
{
  void *fill = bfd_malloc (count);
  if (fill != NULL)
    memset (fill, code ? 0x90 : 0, count);
  return fill;
}
示例#9
0
void *
bfd_arch_default_fill (bfd_size_type count,
		       bfd_boolean is_bigendian ATTRIBUTE_UNUSED,
		       bfd_boolean code ATTRIBUTE_UNUSED)
{
  void *fill = bfd_malloc (count);
  if (fill != NULL)
    memset (fill, 0, count);
  return fill;
}
示例#10
0
static void *
bfd_arch_i386_fill (bfd_size_type count, bfd_boolean code,
		    bfd_boolean long_nop)
{
  /* nop */
  static const char nop_1[] = { 0x90 };
  /* xchg %ax,%ax */
  static const char nop_2[] = { 0x66, 0x90 };
  /* nopl (%[re]ax) */
  static const char nop_3[] = { 0x0f, 0x1f, 0x00 };
  /* nopl 0(%[re]ax) */
  static const char nop_4[] = { 0x0f, 0x1f, 0x40, 0x00 };
  /* nopl 0(%[re]ax,%[re]ax,1) */
  static const char nop_5[] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 };
  /* nopw 0(%[re]ax,%[re]ax,1) */
  static const char nop_6[] = { 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 };
  /* nopl 0L(%[re]ax) */
  static const char nop_7[] = { 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00 };
  /* nopl 0L(%[re]ax,%[re]ax,1) */
  static const char nop_8[] =
    { 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00};
  /* nopw 0L(%[re]ax,%[re]ax,1) */
  static const char nop_9[] =
    { 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
  /* nopw %cs:0L(%[re]ax,%[re]ax,1) */
  static const char nop_10[] =
    { 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
  static const char *const nops[] =
    { nop_1, nop_2, nop_3, nop_4, nop_5,
      nop_6, nop_7, nop_8, nop_9, nop_10 };
  bfd_size_type nop_size = long_nop ? ARRAY_SIZE (nops) : 2;

  void *fill = bfd_malloc (count);
  if (fill == NULL)
    return fill;

  if (code)
    {
      bfd_byte *p = fill;
      while (count >= nop_size)
	{
	  memcpy (p, nops[nop_size - 1], nop_size);
	  p += nop_size;
	  count -= nop_size;
	}
      if (count != 0)
	memcpy (p, nops[count - 1], count);
    }
  else
    memset (fill, 0, count);

  return fill;
}
示例#11
0
struct m68hc11_elf_link_hash_table*
m68hc11_elf_hash_table_create (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_malloc (amt);
  if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
    return NULL;

  memset (ret, 0, amt);
  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
				      _bfd_elf_link_hash_newfunc,
				      sizeof (struct elf_link_hash_entry),
				      M68HC11_ELF_DATA))
    {
      free (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)
    {
      free (ret);
      return NULL;
    }
  if (!bfd_hash_table_init (ret->stub_hash_table, stub_hash_newfunc,
			    sizeof (struct elf32_m68hc11_stub_hash_entry)))
    return NULL;

  ret->stub_bfd = NULL;
  ret->stub_section = 0;
  ret->add_stub_section = NULL;
  ret->sym_cache.abfd = NULL;

  return ret;
}
示例#12
0
void *
_bfd_elf_strtab_save (struct elf_strtab_hash *tab)
{
  struct strtab_save *save;
  size_t idx, size;

  size = sizeof (*save) + (tab->size - 1) * sizeof (save->refcount[0]);
  save = bfd_malloc (size);
  if (save == NULL)
    return save;

  save->size = tab->size;
  for (idx = 1; idx < tab->size; idx++)
    save->refcount[idx] = tab->array[idx]->refcount;
  return save;
}
示例#13
0
long
_bfd_generic_read_minisymbols (bfd *abfd,
			       bfd_boolean dynamic,
			       void **minisymsp,
			       unsigned int *sizep)
{
  long storage;
  asymbol **syms = NULL;
  long symcount;

  if (dynamic)
    storage = bfd_get_dynamic_symtab_upper_bound (abfd);
  else
    storage = bfd_get_symtab_upper_bound (abfd);
  if (storage < 0)
    goto error_return;
  if (storage == 0)
    return 0;

  syms = (asymbol **) bfd_malloc (storage);
  if (syms == NULL)
    goto error_return;

  if (dynamic)
    symcount = bfd_canonicalize_dynamic_symtab (abfd, syms);
  else
    symcount = bfd_canonicalize_symtab (abfd, syms);
  if (symcount < 0)
    goto error_return;

  *minisymsp = syms;
  *sizep = sizeof (asymbol *);

  return symcount;

 error_return:
  bfd_set_error (bfd_error_no_symbols);
  if (syms != NULL)
    free (syms);
  return -1;
}
示例#14
0
static struct bfd_link_hash_table *
h8300_coff_link_hash_table_create (bfd *abfd)
{
  struct h8300_coff_link_hash_table *ret;
  bfd_size_type amt = sizeof (struct h8300_coff_link_hash_table);

  ret = (struct h8300_coff_link_hash_table *) bfd_malloc (amt);
  if (ret == NULL)
    return NULL;
  if (!_bfd_link_hash_table_init (&ret->root.root, abfd,
				  _bfd_generic_link_hash_newfunc))
    {
      free (ret);
      return NULL;
    }

  /* Initialize our data.  */
  ret->vectors_sec = NULL;
  ret->funcvec_hash_table = NULL;

  /* OK.  Everything's initialized, return the base pointer.  */
  return &ret->root.root;
}
/*
 * This function returns a string that describes
 * a section's size, in proper units.
 */
char * pic32_section_size_string (asection *sec)
{
#undef MAX_LEN
#define MAX_LEN 80
#define S1 "size = "
#define S2 " bytes"
#define S3 " PC units"

  char *units;
  char *result = (char *) bfd_malloc (MAX_LEN);

  if (result == (char *) NULL)
    return result;

    units = S2;

  if (sec->rawsize != 0)
    snprintf(result, MAX_LEN, "%s%ld%s", S1, sec->rawsize, units);
  else
    snprintf(result, MAX_LEN, "%s%ld%s", S1, sec->size, units);
    
  return result;
}
示例#16
0
bfd_boolean
_bfd_elf_convert_gnu_properties (bfd *ibfd, asection *isec,
				 bfd *obfd, bfd_byte **ptr,
				 bfd_size_type *ptr_size)
{
  unsigned int size;
  bfd_byte *contents;
  unsigned int align_shift;
  const struct elf_backend_data *bed;
  elf_property_list *list = elf_properties (ibfd);

  bed = get_elf_backend_data (obfd);
  align_shift = bed->s->elfclass == ELFCLASS64 ? 3 : 2;

  /* Get the output .note.gnu.property section size.  */
  size = bfd_get_section_size (isec->output_section);

  /* Update the output .note.gnu.property section alignment.  */
  bfd_set_section_alignment (obfd, isec->output_section, align_shift);

  if (size > bfd_get_section_size (isec))
    {
      contents = (bfd_byte *) bfd_malloc (size);
      free (*ptr);
      *ptr = contents;
    }
  else
    contents = *ptr;

  *ptr_size = size;

  /* Generate the output .note.gnu.property section.  */
  elf_write_gnu_properties (ibfd, contents, list, size, 1 << align_shift);

  return TRUE;
}
示例#17
0
文件: elf-strtab.c 项目: 0mp/freebsd
void
_bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
{
  struct elf_strtab_hash_entry **array, **a, *e;
  bfd_size_type size, amt;

  /* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is
     a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd.
     Besides, indexing with a long long wouldn't give anything but extra
     cycles.  */
  size_t i;

  /* Sort the strings by suffix and length.  */
  amt = tab->size * sizeof (struct elf_strtab_hash_entry *);
  array = bfd_malloc (amt);
  if (array == NULL)
    goto alloc_failure;

  for (i = 1, a = array; i < tab->size; ++i)
    {
      e = tab->array[i];
      if (e->refcount)
	{
	  *a++ = e;
	  /* Adjust the length to not include the zero terminator.  */
	  e->len -= 1;
	}
      else
	e->len = 0;
    }

  size = a - array;
  if (size != 0)
    {
      qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp);

      /* Loop over the sorted array and merge suffixes.  Start from the
	 end because we want eg.

	 s1 -> "d"
	 s2 -> "bcd"
	 s3 -> "abcd"

	 to end up as

	 s3 -> "abcd"
	 s2 _____^
	 s1 _______^

	 ie. we don't want s1 pointing into the old s2.  */
      e = *--a;
      e->len += 1;
      while (--a >= array)
	{
	  struct elf_strtab_hash_entry *cmp = *a;

	  cmp->len += 1;
	  if (is_suffix (e, cmp))
	    {
	      cmp->u.suffix = e;
	      cmp->len = -cmp->len;
	    }
	  else
	    e = cmp;
	}
    }

alloc_failure:
  if (array)
    free (array);

  /* Assign positions to the strings we want to keep.  */
  size = 1;
  for (i = 1; i < tab->size; ++i)
    {
      e = tab->array[i];
      if (e->refcount && e->len > 0)
	{
	  e->u.index = size;
	  size += e->len;
	}
    }

  tab->sec_size = size;

  /* Adjust the rest.  */
  for (i = 1; i < tab->size; ++i)
    {
      e = tab->array[i];
      if (e->refcount && e->len < 0)
	e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len);
    }
}
示例#18
0
文件: reloc16.c 项目: ChrisG0x20/gdb
bfd_byte *
bfd_coff_reloc16_get_relocated_section_contents
  (bfd *in_abfd,
   struct bfd_link_info *link_info,
   struct bfd_link_order *link_order,
   bfd_byte *data,
   bfd_boolean relocatable,
   asymbol **symbols)
{
  /* Get enough memory to hold the stuff.  */
  bfd *input_bfd = link_order->u.indirect.section->owner;
  asection *input_section = link_order->u.indirect.section;
  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
  arelent **reloc_vector;
  long reloc_count;
  bfd_size_type sz;

  if (reloc_size < 0)
    return NULL;

  /* If producing relocatable output, don't bother to relax.  */
  if (relocatable)
    return bfd_generic_get_relocated_section_contents (in_abfd, link_info,
						       link_order,
						       data, relocatable,
						       symbols);

  /* Read in the section.  */
  sz = input_section->rawsize ? input_section->rawsize : input_section->size;
  if (!bfd_get_section_contents (input_bfd, input_section, data, 0, sz))
    return NULL;

  reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
  if (!reloc_vector && reloc_size != 0)
    return NULL;

  reloc_count = bfd_canonicalize_reloc (input_bfd,
					input_section,
					reloc_vector,
					symbols);
  if (reloc_count < 0)
    {
      free (reloc_vector);
      return NULL;
    }

  if (reloc_count > 0)
    {
      arelent **parent = reloc_vector;
      arelent *reloc;
      unsigned int dst_address = 0;
      unsigned int src_address = 0;
      unsigned int run;
      unsigned int idx;

      /* Find how long a run we can do.  */
      while (dst_address < link_order->size)
	{
	  reloc = *parent;
	  if (reloc)
	    {
	      /* Note that the relaxing didn't tie up the addresses in the
		 relocation, so we use the original address to work out the
		 run of non-relocated data.  */
	      run = reloc->address - src_address;
	      parent++;
	    }
	  else
	    {
	      run = link_order->size - dst_address;
	    }

	  /* Copy the bytes.  */
	  for (idx = 0; idx < run; idx++)
	    data[dst_address++] = data[src_address++];

	  /* Now do the relocation.  */
	  if (reloc)
	    {
	      bfd_coff_reloc16_extra_cases (input_bfd, link_info, link_order,
					    reloc, data, &src_address,
					    &dst_address);
	    }
	}
    }
  free ((char *) reloc_vector);
  return data;
}
示例#19
0
文件: reloc16.c 项目: ChrisG0x20/gdb
bfd_boolean
bfd_coff_reloc16_relax_section (bfd *abfd,
				asection *input_section,
				struct bfd_link_info *link_info,
				bfd_boolean *again)
{
  /* Get enough memory to hold the stuff.  */
  bfd *input_bfd = input_section->owner;
  unsigned *shrinks;
  unsigned shrink = 0;
  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
  arelent **reloc_vector = NULL;
  long reloc_count;

  if (bfd_link_relocatable (link_info))
    (*link_info->callbacks->einfo)
      (_("%P%F: --relax and -r may not be used together\n"));

  /* We only do global relaxation once.  It is not safe to do it multiple
     times (see discussion of the "shrinks" array below).  */
  *again = FALSE;

  if (reloc_size < 0)
    return FALSE;

  reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
  if (!reloc_vector && reloc_size > 0)
    return FALSE;

  /* Get the relocs and think about them.  */
  reloc_count =
    bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
			    _bfd_generic_link_get_symbols (input_bfd));
  if (reloc_count < 0)
    {
      free (reloc_vector);
      return FALSE;
    }

  /* The reloc16.c and related relaxing code is very simple, the price
     for that simplicity is we can only call this function once for
     each section.

     So, to get the best results within that limitation, we do multiple
     relaxing passes over each section here.  That involves keeping track
     of the "shrink" at each reloc in the section.  This allows us to
     accurately determine the relative location of two relocs within
     this section.

     In theory, if we kept the "shrinks" array for each section for the
     entire link, we could use the generic relaxing code in the linker
     and get better results, particularly for jsr->bsr and 24->16 bit
     memory reference relaxations.  */

  if (reloc_count > 0)
    {
      int another_pass = 0;
      bfd_size_type amt;

      /* Allocate and initialize the shrinks array for this section.
	 The last element is used as an accumulator of shrinks.  */
      amt = reloc_count + 1;
      amt *= sizeof (unsigned);
      shrinks = (unsigned *) bfd_zmalloc (amt);

      /* Loop until nothing changes in this section.  */
      do
	{
	  arelent **parent;
	  unsigned int i;
	  long j;

	  another_pass = 0;

	  for (i = 0, parent = reloc_vector; *parent; parent++, i++)
	    {
	      /* Let the target/machine dependent code examine each reloc
		 in this section and attempt to shrink it.  */
	      shrink = bfd_coff_reloc16_estimate (abfd, input_section, *parent,
						  shrinks[i], link_info);

	      /* If it shrunk, note it in the shrinks array and set up for
		 another pass.  */
	      if (shrink != shrinks[i])
		{
		  another_pass = 1;
		  for (j = i + 1; j <= reloc_count; j++)
		    shrinks[j] += shrink - shrinks[i];
		}
	    }
	}
      while (another_pass);

      shrink = shrinks[reloc_count];
      free ((char *) shrinks);
    }

  input_section->rawsize = input_section->size;
  input_section->size -= shrink;
  free ((char *) reloc_vector);
  return TRUE;
}
示例#20
0
bfd_boolean
bfd_check_format_matches(bfd *abfd, bfd_format format, char ***matching)
{
  const bfd_target * const *target;
  const bfd_target **matching_vector = (const bfd_target **)NULL;
  const bfd_target *save_targ, *right_targ, *ar_right_targ;
  int match_count;
  int ar_match_index;

  if (!bfd_read_p(abfd)
      || ((unsigned int)abfd->format >= (unsigned int)bfd_type_end))
    {
      bfd_set_error(bfd_error_invalid_operation);
      return FALSE;
    }

  if (abfd->format != bfd_unknown) {
    return (abfd->format == format);
  }

  /* Since the target type was defaulted, check them all in the hope that
   * one will be uniquely recognized: */
  save_targ = abfd->xvec;
  match_count = 0;
  ar_match_index = (int)_bfd_target_vector_entries;

  if (matching)
    {
      bfd_size_type amt;

      *matching = NULL;
      amt = (sizeof(*matching_vector) * 2 * _bfd_target_vector_entries);
      matching_vector = (const bfd_target **)bfd_malloc(amt);
      if (!matching_vector) {
	return FALSE;
      }
    }

  right_targ = 0;
  ar_right_targ = 0;

  /* Presume the answer is yes: */
  abfd->format = format;

  /* If the target type was explicitly specified, then just check that
   * target: */
  if (!abfd->target_defaulted)
    {
      if (bfd_seek(abfd, (file_ptr)0L, SEEK_SET) != 0)	/* rewind! */
	{
	  if (matching)
	    free(matching_vector);
	  return FALSE;
	}

      right_targ = BFD_SEND_FMT(abfd, _bfd_check_format, (abfd));

      if (right_targ)
	{
	  abfd->xvec = right_targ;	/* Set the target as returned.  */

	  if (matching)
	    free(matching_vector);

	  /* If the file was opened for update, then `output_has_begun'
	     some time ago when the file was created.  Do not recompute
	     sections sizes or alignments in _bfd_set_section_contents.
	     We can not set this flag until after checking the format,
	     because it will interfere with creation of BFD sections.  */
	  if (abfd->direction == both_direction)
	    abfd->output_has_begun = TRUE;

	  return TRUE;		    /* File position has moved, BTW.  */
	}

      /* For a long time the code has dropped through to check all
	 targets if the specified target was wrong.  I don't know why,
	 and I'm reluctant to change it.  However, in the case of an
	 archive, it can cause problems.  If the specified target does
	 not permit archives (e.g., the binary target), then we should
	 not allow some other target to recognize it as an archive, but
	 should instead allow the specified target to recognize it as an
	 object.  When I first made this change, it broke the PE target,
	 because the specified pei-i386 target did not recognize the
	 actual pe-i386 archive.  Since there may be other problems of
	 this sort, I changed this test to check only for the binary
	 target.  */
      if ((format == bfd_archive) && (save_targ == &binary_vec))
	{
	  abfd->xvec = save_targ;
	  abfd->format = bfd_unknown;

	  if (matching)
	    free(matching_vector);

	  bfd_set_error(bfd_error_file_not_recognized);

	  return FALSE;
	}
    }

  for (target = bfd_target_vector; *target != NULL; target++)
    {
      const bfd_target *temp;
      bfd_error_type err;

      if (*target == &binary_vec)
	continue;

      abfd->xvec = *target;	/* Change BFD's target temporarily.  */

      if (bfd_seek(abfd, (file_ptr)0L, SEEK_SET) != 0)
	{
	  if (matching)
	    free(matching_vector);
	  return FALSE;
	}

      /* If _bfd_check_format neglects to set bfd_error, assume
	 bfd_error_wrong_format.  We didn't used to even pay any
	 attention to bfd_error, so I suspect that some
	 _bfd_check_format might have this problem.  */
      bfd_set_error(bfd_error_wrong_format);

      temp = BFD_SEND_FMT(abfd, _bfd_check_format, (abfd));

      if (temp)
	{
	  /* This format checks out as ok!  */
	  right_targ = temp;

	  /* If this is the default target, accept it, even if other
	     targets might match.  People who want those other targets
	     have to set the GNUTARGET variable.  */
	  if (temp == bfd_default_vector[0])
	    {
	      match_count = 1;
	      break;
	    }

	  if (matching)
	    matching_vector[match_count] = temp;

	  match_count++;
	}
      else if (((err = bfd_get_error()) == bfd_error_wrong_object_format)
	       || (err == bfd_error_file_ambiguously_recognized))
	{
	  /* An archive with objects of the wrong type, or an
	     ambiguous match.  We want this target to match if we get
	     no better matches.  */
	  if (ar_right_targ != bfd_default_vector[0])
	    ar_right_targ = *target;
	  if (matching)
	    matching_vector[ar_match_index] = *target;
	  ar_match_index++;
	}
      else if (err != bfd_error_wrong_format)
	{
	  abfd->xvec = save_targ;
	  abfd->format = bfd_unknown;

	  if (matching)
	    free(matching_vector);

	  return FALSE;
	}
    }

  if (match_count == 0)
    {
      /* Try partial matches: */
      right_targ = ar_right_targ;

      if (right_targ == bfd_default_vector[0])
	{
	  match_count = 1;
	}
      else
	{
	  match_count = (int)((size_t)ar_match_index - _bfd_target_vector_entries);

	  if (matching && (match_count > 1))
	    memcpy(matching_vector,
                   (matching_vector + _bfd_target_vector_entries),
                   (sizeof(*matching_vector) * (size_t)match_count));
	}
    }

  if (match_count > 1
      && bfd_associated_vector != NULL
      && matching)
    {
      const bfd_target * const *assoc = bfd_associated_vector;

      while ((right_targ = *assoc++) != NULL)
	{
	  int i = match_count;

	  while (--i >= 0)
	    if (matching_vector[i] == right_targ)
	      break;

	  if (i >= 0)
	    {
	      match_count = 1;
	      break;
	    }
	}
    }

  if (match_count == 1)
    {
      abfd->xvec = right_targ;		/* Change BFD's target permanently.  */

      if (matching)
	free (matching_vector);

      /* If the file was opened for update, then `output_has_begun'
	 some time ago when the file was created.  Do not recompute
	 sections sizes or alignments in _bfd_set_section_contents.
	 We can not set this flag until after checking the format,
	 because it will interfere with creation of BFD sections.  */
      if (abfd->direction == both_direction)
	abfd->output_has_begun = TRUE;

      return TRUE;			/* File position has moved, BTW.  */
    }

  abfd->xvec = save_targ;		/* Restore original target type.  */
  abfd->format = bfd_unknown;		/* Restore original format.  */

  if (match_count == 0)
    {
      bfd_set_error (bfd_error_file_not_recognized);

      if (matching)
	free (matching_vector);
    }
  else
    {
      bfd_set_error (bfd_error_file_ambiguously_recognized);

      if (matching)
	{
	  *matching = (char **) matching_vector;
	  matching_vector[match_count] = NULL;
	  /* Return target names.  This is a little nasty.  Maybe we
	     should do another bfd_malloc?  */
	  while (--match_count >= 0)
	    {
	      const char *name = matching_vector[match_count]->name;
	      *(const char **) &matching_vector[match_count] = name;
	    }
	}
    }

  return FALSE;
}
示例#21
0
/* Parse an object attributes section.  */
void
_bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
{
  bfd_byte *contents;
  bfd_byte *p;
  bfd_vma len;
  const char *std_sec;

  contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
  if (!contents)
    return;
  if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
				 hdr->sh_size))
    {
      free (contents);
      return;
    }
  p = contents;
  std_sec = get_elf_backend_data (abfd)->obj_attrs_vendor;
  if (*(p++) == 'A')
    {
      len = hdr->sh_size - 1;
      while (len > 0)
	{
	  int namelen;
	  bfd_vma section_len;
	  int vendor;

	  section_len = bfd_get_32 (abfd, p);
	  p += 4;
	  if (section_len > len)
	    section_len = len;
	  len -= section_len;
	  namelen = strlen ((char *) p) + 1;
	  section_len -= namelen + 4;
	  if (std_sec && strcmp ((char *) p, std_sec) == 0)
	    vendor = OBJ_ATTR_PROC;
	  else if (strcmp ((char *) p, "gnu") == 0)
	    vendor = OBJ_ATTR_GNU;
	  else
	    {
	      /* Other vendor section.  Ignore it.  */
	      p += namelen + section_len;
	      continue;
	    }

	  p += namelen;
	  while (section_len > 0)
	    {
	      int tag;
	      unsigned int n;
	      unsigned int val;
	      bfd_vma subsection_len;
	      bfd_byte *end;

	      tag = read_unsigned_leb128 (abfd, p, &n);
	      p += n;
	      subsection_len = bfd_get_32 (abfd, p);
	      p += 4;
	      if (subsection_len > section_len)
		subsection_len = section_len;
	      section_len -= subsection_len;
	      subsection_len -= n + 4;
	      end = p + subsection_len;
	      switch (tag)
		{
		case Tag_File:
		  while (p < end)
		    {
		      int type;

		      tag = read_unsigned_leb128 (abfd, p, &n);
		      p += n;
		      type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
		      switch (type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL))
			{
			case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL:
			  val = read_unsigned_leb128 (abfd, p, &n);
			  p += n;
			  bfd_elf_add_obj_attr_int_string (abfd, vendor, tag,
							   val, (char *)p);
			  p += strlen ((char *)p) + 1;
			  break;
			case ATTR_TYPE_FLAG_STR_VAL:
			  bfd_elf_add_obj_attr_string (abfd, vendor, tag,
						       (char *)p);
			  p += strlen ((char *)p) + 1;
			  break;
			case ATTR_TYPE_FLAG_INT_VAL:
			  val = read_unsigned_leb128 (abfd, p, &n);
			  p += n;
			  bfd_elf_add_obj_attr_int (abfd, vendor, tag, val);
			  break;
			default:
			  abort ();
			}
		    }
		  break;
		case Tag_Section:
		case Tag_Symbol:
		  /* Don't have anywhere convenient to attach these.
		     Fall through for now.  */
		default:
		  /* Ignore things we don't kow about.  */
		  p += subsection_len;
		  subsection_len = 0;
		  break;
		}
	    }
	}
    }
  free (contents);
}
示例#22
0
void
_bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
{
  struct elf_strtab_hash_entry **array, **a, *e;
  bfd_size_type amt, sec_size;
  size_t size, i;

  /* Sort the strings by suffix and length.  */
  amt = tab->size;
  amt *= sizeof (struct elf_strtab_hash_entry *);
  array = (struct elf_strtab_hash_entry **) bfd_malloc (amt);
  if (array == NULL)
    goto alloc_failure;

  for (i = 1, a = array; i < tab->size; ++i)
    {
      e = tab->array[i];
      if (e->refcount)
	{
	  *a++ = e;
	  /* Adjust the length to not include the zero terminator.  */
	  e->len -= 1;
	}
      else
	e->len = 0;
    }

  size = a - array;
  if (size != 0)
    {
      qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp);

      /* Loop over the sorted array and merge suffixes.  Start from the
	 end because we want eg.

	 s1 -> "d"
	 s2 -> "bcd"
	 s3 -> "abcd"

	 to end up as

	 s3 -> "abcd"
	 s2 _____^
	 s1 _______^

	 ie. we don't want s1 pointing into the old s2.  */
      e = *--a;
      e->len += 1;
      while (--a >= array)
	{
	  struct elf_strtab_hash_entry *cmp = *a;

	  cmp->len += 1;
	  if (is_suffix (e, cmp))
	    {
	      cmp->u.suffix = e;
	      cmp->len = -cmp->len;
	    }
	  else
	    e = cmp;
	}
    }

alloc_failure:
  if (array)
    free (array);

  /* Assign positions to the strings we want to keep.  */
  sec_size = 1;
  for (i = 1; i < tab->size; ++i)
    {
      e = tab->array[i];
      if (e->refcount && e->len > 0)
	{
	  e->u.index = sec_size;
	  sec_size += e->len;
	}
    }

  tab->sec_size = sec_size;

  /* Adjust the rest.  */
  for (i = 1; i < tab->size; ++i)
    {
      e = tab->array[i];
      if (e->refcount && e->len < 0)
	e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len);
    }
}
示例#23
0
bfd_boolean
bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
{
    bfd_size_type sz;
    bfd_byte *p = *ptr;
    bfd_boolean ret;
    bfd_size_type save_size;
    bfd_size_type save_rawsize;
    bfd_byte *compressed_buffer;
    unsigned int compression_header_size;

    if (abfd->direction != write_direction && sec->rawsize != 0)
        sz = sec->rawsize;
    else
        sz = sec->size;
    if (sz == 0)
    {
        *ptr = NULL;
        return TRUE;
    }

    switch (sec->compress_status)
    {
    case COMPRESS_SECTION_NONE:
        if (p == NULL)
        {
            p = (bfd_byte *) bfd_malloc (sz);
            if (p == NULL)
            {
                /* PR 20801: Provide a more helpful error message.  */
                if (bfd_get_error () == bfd_error_no_memory)
                    _bfd_error_handler
                    /* xgettext:c-format */
                    (_("error: %B(%A) is too large (%#lx bytes)"),
                     abfd, sec, (long) sz);
                return FALSE;
            }
        }

        if (!bfd_get_section_contents (abfd, sec, p, 0, sz))
        {
            if (*ptr != p)
                free (p);
            return FALSE;
        }
        *ptr = p;
        return TRUE;

    case DECOMPRESS_SECTION_SIZED:
        /* Read in the full compressed section contents.  */
        compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size);
        if (compressed_buffer == NULL)
            return FALSE;
        save_rawsize = sec->rawsize;
        save_size = sec->size;
        /* Clear rawsize, set size to compressed size and set compress_status
        to COMPRESS_SECTION_NONE.  If the compressed size is bigger than
         the uncompressed size, bfd_get_section_contents will fail.  */
        sec->rawsize = 0;
        sec->size = sec->compressed_size;
        sec->compress_status = COMPRESS_SECTION_NONE;
        ret = bfd_get_section_contents (abfd, sec, compressed_buffer,
                                        0, sec->compressed_size);
        /* Restore rawsize and size.  */
        sec->rawsize = save_rawsize;
        sec->size = save_size;
        sec->compress_status = DECOMPRESS_SECTION_SIZED;
        if (!ret)
            goto fail_compressed;

        if (p == NULL)
            p = (bfd_byte *) bfd_malloc (sz);
        if (p == NULL)
            goto fail_compressed;

        compression_header_size = bfd_get_compression_header_size (abfd, sec);
        if (compression_header_size == 0)
            /* Set header size to the zlib header size if it is a
               SHF_COMPRESSED section.  */
            compression_header_size = 12;
        if (!decompress_contents (compressed_buffer + compression_header_size,
                                  sec->compressed_size, p, sz))
        {
            bfd_set_error (bfd_error_bad_value);
            if (p != *ptr)
                free (p);
fail_compressed:
            free (compressed_buffer);
            return FALSE;
        }

        free (compressed_buffer);
        *ptr = p;
        return TRUE;

    case COMPRESS_SECTION_DONE:
        if (sec->contents == NULL)
            return FALSE;
        if (p == NULL)
        {
            p = (bfd_byte *) bfd_malloc (sz);
            if (p == NULL)
                return FALSE;
            *ptr = p;
        }
        /* PR 17512; file: 5bc29788.  */
        if (p != sec->contents)
            memcpy (p, sec->contents, sz);
        return TRUE;

    default:
        abort ();
    }
}
示例#24
0
bfd_boolean
_bfd_elf_discard_section_eh_frame
   (bfd *abfd, struct bfd_link_info *info, asection *sec,
    bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *),
    struct elf_reloc_cookie *cookie)
{
#define REQUIRE(COND)					\
  do							\
    if (!(COND))					\
      goto free_no_table;				\
  while (0)

  bfd_byte *ehbuf = NULL, *buf;
  bfd_byte *last_fde;
  struct eh_cie_fde *ent, *this_inf;
  unsigned int hdr_length, hdr_id;
  struct extended_cie
    {
      struct cie cie;
      unsigned int offset;
      unsigned int usage_count;
      unsigned int entry;
    } *ecies = NULL, *ecie;
  unsigned int ecie_count = 0, ecie_alloced = 0;
  struct cie *cie;
  struct elf_link_hash_table *htab;
  struct eh_frame_hdr_info *hdr_info;
  struct eh_frame_sec_info *sec_info = NULL;
  unsigned int offset;
  unsigned int ptr_size;
  unsigned int entry_alloced;

  if (sec->size == 0)
    {
      /* This file does not contain .eh_frame information.  */
      return FALSE;
    }

  if (bfd_is_abs_section (sec->output_section))
    {
      /* At least one of the sections is being discarded from the
	 link, so we should just ignore them.  */
      return FALSE;
    }

  htab = elf_hash_table (info);
  hdr_info = &htab->eh_info;

  if (hdr_info->cies == NULL && !info->relocatable)
    hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free);

  /* Read the frame unwind information from abfd.  */

  REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf));

  if (sec->size >= 4
      && bfd_get_32 (abfd, ehbuf) == 0
      && cookie->rel == cookie->relend)
    {
      /* Empty .eh_frame section.  */
      free (ehbuf);
      return FALSE;
    }

  /* If .eh_frame section size doesn't fit into int, we cannot handle
     it (it would need to use 64-bit .eh_frame format anyway).  */
  REQUIRE (sec->size == (unsigned int) sec->size);

  ptr_size = (get_elf_backend_data (abfd)
	      ->elf_backend_eh_frame_address_size (abfd, sec));
  REQUIRE (ptr_size != 0);

  buf = ehbuf;
  sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info)
			  + 99 * sizeof (struct eh_cie_fde));
  REQUIRE (sec_info);

  entry_alloced = 100;

#define ENSURE_NO_RELOCS(buf)				\
  REQUIRE (!(cookie->rel < cookie->relend		\
	     && (cookie->rel->r_offset			\
		 < (bfd_size_type) ((buf) - ehbuf))	\
	     && cookie->rel->r_info != 0))

#define SKIP_RELOCS(buf)				\
  while (cookie->rel < cookie->relend			\
	 && (cookie->rel->r_offset			\
	     < (bfd_size_type) ((buf) - ehbuf)))	\
    cookie->rel++

#define GET_RELOC(buf)					\
  ((cookie->rel < cookie->relend			\
    && (cookie->rel->r_offset				\
	== (bfd_size_type) ((buf) - ehbuf)))		\
   ? cookie->rel : NULL)

  for (;;)
    {
      char *aug;
      bfd_byte *start, *end, *insns, *insns_end;
      bfd_size_type length;
      unsigned int set_loc_count;

      if (sec_info->count == entry_alloced)
	{
	  sec_info = bfd_realloc (sec_info,
				  sizeof (struct eh_frame_sec_info)
				  + ((entry_alloced + 99)
				     * sizeof (struct eh_cie_fde)));
	  REQUIRE (sec_info);

	  memset (&sec_info->entry[entry_alloced], 0,
		  100 * sizeof (struct eh_cie_fde));
	  entry_alloced += 100;
	}

      this_inf = sec_info->entry + sec_info->count;
      last_fde = buf;

      if ((bfd_size_type) (buf - ehbuf) == sec->size)
	break;

      /* Read the length of the entry.  */
      REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4));
      hdr_length = bfd_get_32 (abfd, buf - 4);

      /* 64-bit .eh_frame is not supported.  */
      REQUIRE (hdr_length != 0xffffffff);

      /* The CIE/FDE must be fully contained in this input section.  */
      REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size);
      end = buf + hdr_length;

      this_inf->offset = last_fde - ehbuf;
      this_inf->size = 4 + hdr_length;

      if (hdr_length == 0)
	{
	  /* A zero-length CIE should only be found at the end of
	     the section.  */
	  REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size);
	  ENSURE_NO_RELOCS (buf);
	  sec_info->count++;
	  break;
	}

      REQUIRE (skip_bytes (&buf, end, 4));
      hdr_id = bfd_get_32 (abfd, buf - 4);

      if (hdr_id == 0)
	{
	  unsigned int initial_insn_length;

	  /* CIE  */
	  this_inf->cie = 1;

	  if (ecie_count == ecie_alloced)
	    {
	      ecies = bfd_realloc (ecies,
				   (ecie_alloced + 20) * sizeof (*ecies));
	      REQUIRE (ecies);
	      memset (&ecies[ecie_alloced], 0, 20 * sizeof (*ecies));
	      ecie_alloced += 20;
	    }

	  cie = &ecies[ecie_count].cie;
	  ecies[ecie_count].offset = this_inf->offset;
	  ecies[ecie_count++].entry = sec_info->count;
	  cie->length = hdr_length;
	  start = buf;
	  REQUIRE (read_byte (&buf, end, &cie->version));

	  /* Cannot handle unknown versions.  */
	  REQUIRE (cie->version == 1 || cie->version == 3);
	  REQUIRE (strlen ((char *) buf) < sizeof (cie->augmentation));

	  strcpy (cie->augmentation, (char *) buf);
	  buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1;
	  ENSURE_NO_RELOCS (buf);
	  if (buf[0] == 'e' && buf[1] == 'h')
	    {
	      /* GCC < 3.0 .eh_frame CIE */
	      /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__
		 is private to each CIE, so we don't need it for anything.
		 Just skip it.  */
	      REQUIRE (skip_bytes (&buf, end, ptr_size));
	      SKIP_RELOCS (buf);
	    }
	  REQUIRE (read_uleb128 (&buf, end, &cie->code_align));
	  REQUIRE (read_sleb128 (&buf, end, &cie->data_align));
	  if (cie->version == 1)
	    {
	      REQUIRE (buf < end);
	      cie->ra_column = *buf++;
	    }
	  else
	    REQUIRE (read_uleb128 (&buf, end, &cie->ra_column));
	  ENSURE_NO_RELOCS (buf);
	  cie->lsda_encoding = DW_EH_PE_omit;
	  cie->fde_encoding = DW_EH_PE_omit;
	  cie->per_encoding = DW_EH_PE_omit;
	  aug = cie->augmentation;
	  if (aug[0] != 'e' || aug[1] != 'h')
	    {
	      if (*aug == 'z')
		{
		  aug++;
		  REQUIRE (read_uleb128 (&buf, end, &cie->augmentation_size));
	  	  ENSURE_NO_RELOCS (buf);
		}

	      while (*aug != '\0')
		switch (*aug++)
		  {
		  case 'L':
		    REQUIRE (read_byte (&buf, end, &cie->lsda_encoding));
		    ENSURE_NO_RELOCS (buf);
		    REQUIRE (get_DW_EH_PE_width (cie->lsda_encoding, ptr_size));
		    break;
		  case 'R':
		    REQUIRE (read_byte (&buf, end, &cie->fde_encoding));
		    ENSURE_NO_RELOCS (buf);
		    REQUIRE (get_DW_EH_PE_width (cie->fde_encoding, ptr_size));
		    break;
		  case 'S':
		    break;
		  case 'P':
		    {
		      int per_width;

		      REQUIRE (read_byte (&buf, end, &cie->per_encoding));
		      per_width = get_DW_EH_PE_width (cie->per_encoding,
						      ptr_size);
		      REQUIRE (per_width);
		      if ((cie->per_encoding & 0xf0) == DW_EH_PE_aligned)
			{
			  length = -(buf - ehbuf) & (per_width - 1);
			  REQUIRE (skip_bytes (&buf, end, length));
			}
		      ENSURE_NO_RELOCS (buf);
		      /* Ensure we have a reloc here.  */
		      if (GET_RELOC (buf) != NULL)
			{
			  unsigned long r_symndx;

#ifdef BFD64
			  if (ptr_size == 8)
			    r_symndx = ELF64_R_SYM (cookie->rel->r_info);
			  else
#endif
			    r_symndx = ELF32_R_SYM (cookie->rel->r_info);
			  if (r_symndx >= cookie->locsymcount
			      || ELF_ST_BIND (cookie->locsyms[r_symndx]
					      .st_info) != STB_LOCAL)
			    {
			      struct elf_link_hash_entry *h;

			      r_symndx -= cookie->extsymoff;
			      h = cookie->sym_hashes[r_symndx];

			      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;

			      cie->personality.h = h;
			    }
			  else
			    {
			      Elf_Internal_Sym *sym;
			      asection *sym_sec;
			      bfd_vma val;

			      sym = &cookie->locsyms[r_symndx];
			      sym_sec = (bfd_section_from_elf_index
					 (abfd, sym->st_shndx));
			      if (sym_sec != NULL)
				{
				  if (sym_sec->kept_section != NULL)
				    sym_sec = sym_sec->kept_section;
				  if (sym_sec->output_section != NULL)
				    {
				      val = (sym->st_value
					     + sym_sec->output_offset
					     + sym_sec->output_section->vma);
				      cie->personality.val = val;
				      cie->local_personality = 1;
				    }
				}
			    }

			  /* Cope with MIPS-style composite relocations.  */
			  do
			    cookie->rel++;
			  while (GET_RELOC (buf) != NULL);
			}
		      REQUIRE (skip_bytes (&buf, end, per_width));
		      REQUIRE (cie->local_personality || cie->personality.h);
		    }
		    break;
		  default:
		    /* Unrecognized augmentation. Better bail out.  */
		    goto free_no_table;
		  }
	    }

	  /* For shared libraries, try to get rid of as many RELATIVE relocs
	     as possible.  */
	  if (info->shared
	      && (get_elf_backend_data (abfd)
		  ->elf_backend_can_make_relative_eh_frame
		  (abfd, info, sec)))
	    {
	      if ((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr)
		cie->make_relative = 1;
	      /* If the CIE doesn't already have an 'R' entry, it's fairly
		 easy to add one, provided that there's no aligned data
		 after the augmentation string.  */
	      else if (cie->fde_encoding == DW_EH_PE_omit
		       && (cie->per_encoding & 0xf0) != DW_EH_PE_aligned)
		{
		  if (*cie->augmentation == 0)
		    this_inf->add_augmentation_size = 1;
		  this_inf->add_fde_encoding = 1;
		  cie->make_relative = 1;
		}
	    }

	  if (info->shared
	      && (get_elf_backend_data (abfd)
		  ->elf_backend_can_make_lsda_relative_eh_frame
		  (abfd, info, sec))
	      && (cie->lsda_encoding & 0xf0) == DW_EH_PE_absptr)
	    cie->make_lsda_relative = 1;

	  /* If FDE encoding was not specified, it defaults to
	     DW_EH_absptr.  */
	  if (cie->fde_encoding == DW_EH_PE_omit)
	    cie->fde_encoding = DW_EH_PE_absptr;

	  initial_insn_length = end - buf;
	  if (initial_insn_length <= sizeof (cie->initial_instructions))
	    {
	      cie->initial_insn_length = initial_insn_length;
	      memcpy (cie->initial_instructions, buf, initial_insn_length);
	    }
	  insns = buf;
	  buf += initial_insn_length;
	  ENSURE_NO_RELOCS (buf);
	}
      else
	{
	  /* Find the corresponding CIE.  */
	  unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
	  for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
	    if (cie_offset == ecie->offset)
	      break;

	  /* Ensure this FDE references one of the CIEs in this input
	     section.  */
	  REQUIRE (ecie != ecies + ecie_count);
	  cie = &ecie->cie;

	  ENSURE_NO_RELOCS (buf);
	  REQUIRE (GET_RELOC (buf));

	  if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie))
	    /* This is a FDE against a discarded section.  It should
	       be deleted.  */
	    this_inf->removed = 1;
	  else
	    {
	      if (info->shared
		  && (((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr
		       && cie->make_relative == 0)
		      || (cie->fde_encoding & 0xf0) == DW_EH_PE_aligned))
		{
		  /* If a shared library uses absolute pointers
		     which we cannot turn into PC relative,
		     don't create the binary search table,
		     since it is affected by runtime relocations.  */
		  hdr_info->table = FALSE;
		  (*info->callbacks->einfo)
		    (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr"
		       " table being created.\n"), abfd, sec);
		}
	      ecie->usage_count++;
	      hdr_info->fde_count++;
	      this_inf->cie_inf = (void *) (ecie - ecies);
	    }

	  /* Skip the initial location and address range.  */
	  start = buf;
	  length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
	  REQUIRE (skip_bytes (&buf, end, 2 * length));

	  /* Skip the augmentation size, if present.  */
	  if (cie->augmentation[0] == 'z')
	    REQUIRE (read_uleb128 (&buf, end, &length));
	  else
	    length = 0;

	  /* Of the supported augmentation characters above, only 'L'
	     adds augmentation data to the FDE.  This code would need to
	     be adjusted if any future augmentations do the same thing.  */
	  if (cie->lsda_encoding != DW_EH_PE_omit)
	    {
	      this_inf->lsda_offset = buf - start;
	      /* If there's no 'z' augmentation, we don't know where the
		 CFA insns begin.  Assume no padding.  */
	      if (cie->augmentation[0] != 'z')
		length = end - buf;
	    }

	  /* Skip over the augmentation data.  */
	  REQUIRE (skip_bytes (&buf, end, length));
	  insns = buf;

	  buf = last_fde + 4 + hdr_length;
	  SKIP_RELOCS (buf);
	}

      /* Try to interpret the CFA instructions and find the first
	 padding nop.  Shrink this_inf's size so that it doesn't
	 include the padding.  */
      length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
      set_loc_count = 0;
      insns_end = skip_non_nops (insns, end, length, &set_loc_count);
      /* If we don't understand the CFA instructions, we can't know
	 what needs to be adjusted there.  */
      if (insns_end == NULL
	  /* For the time being we don't support DW_CFA_set_loc in
	     CIE instructions.  */
	  || (set_loc_count && this_inf->cie))
	goto free_no_table;
      this_inf->size -= end - insns_end;
      if (insns_end != end && this_inf->cie)
	{
	  cie->initial_insn_length -= end - insns_end;
	  cie->length -= end - insns_end;
	}
      if (set_loc_count
	  && ((cie->fde_encoding & 0xf0) == DW_EH_PE_pcrel
	      || cie->make_relative))
	{
	  unsigned int cnt;
	  bfd_byte *p;

	  this_inf->set_loc = bfd_malloc ((set_loc_count + 1)
					  * sizeof (unsigned int));
	  REQUIRE (this_inf->set_loc);
	  this_inf->set_loc[0] = set_loc_count;
	  p = insns;
	  cnt = 0;
	  while (p < end)
	    {
	      if (*p == DW_CFA_set_loc)
		this_inf->set_loc[++cnt] = p + 1 - start;
	      REQUIRE (skip_cfa_op (&p, end, length));
	    }
	}

      this_inf->fde_encoding = cie->fde_encoding;
      this_inf->lsda_encoding = cie->lsda_encoding;
      sec_info->count++;
    }

  elf_section_data (sec)->sec_info = sec_info;
  sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME;

  /* Look at all CIEs in this section and determine which can be
     removed as unused, which can be merged with previous duplicate
     CIEs and which need to be kept.  */
  for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
    {
      if (ecie->usage_count == 0)
	{
	  sec_info->entry[ecie->entry].removed = 1;
	  continue;
	}
      ecie->cie.output_sec = sec->output_section;
      ecie->cie.cie_inf = sec_info->entry + ecie->entry;
      cie_compute_hash (&ecie->cie);
      if (hdr_info->cies != NULL)
	{
	  void **loc = htab_find_slot_with_hash (hdr_info->cies, &ecie->cie,
						 ecie->cie.hash, INSERT);
	  if (loc != NULL)
	    {
	      if (*loc != HTAB_EMPTY_ENTRY)
		{
		  sec_info->entry[ecie->entry].removed = 1;
		  ecie->cie.cie_inf = ((struct cie *) *loc)->cie_inf;
		  continue;
		}

	      *loc = malloc (sizeof (struct cie));
	      if (*loc == NULL)
		*loc = HTAB_DELETED_ENTRY;
	      else
		memcpy (*loc, &ecie->cie, sizeof (struct cie));
	    }
	}
      ecie->cie.cie_inf->make_relative = ecie->cie.make_relative;
      ecie->cie.cie_inf->make_lsda_relative = ecie->cie.make_lsda_relative;
      ecie->cie.cie_inf->per_encoding_relative
	= (ecie->cie.per_encoding & 0x70) == DW_EH_PE_pcrel;
    }

  /* Ok, now we can assign new offsets.  */
  offset = 0;
  for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
    if (!ent->removed)
      {
	if (!ent->cie)
	  {
	    ecie = ecies + (bfd_hostptr_t) ent->cie_inf;
	    ent->cie_inf = ecie->cie.cie_inf;
	  }
	ent->new_offset = offset;
	offset += size_of_output_cie_fde (ent, ptr_size);
      }

  /* Resize the sec as needed.  */
  sec->rawsize = sec->size;
  sec->size = offset;

  free (ehbuf);
  if (ecies)
    free (ecies);
  return offset != sec->rawsize;

free_no_table:
  (*info->callbacks->einfo)
    (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"),
     abfd, sec);
  if (ehbuf)
    free (ehbuf);
  if (sec_info)
    free (sec_info);
  if (ecies)
    free (ecies);
  hdr_info->table = FALSE;
  return FALSE;

#undef REQUIRE
}
示例#25
0
bfd_boolean
xcoff64_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd)
{
  struct core_dumpxx core;
  char *path, *s;
  size_t alloc;
  const char *str1, *str2;
  bfd_boolean return_value = FALSE;

  /* Get the header.  */
  if (bfd_seek (core_bfd, 0, SEEK_SET) != 0)
    return return_value;

  if (sizeof (struct core_dumpxx) !=
      bfd_bread (&core, sizeof (struct core_dumpxx), core_bfd))
    return return_value;

  if (bfd_seek (core_bfd, core.c_loader, SEEK_SET) != 0)
    return return_value;

  alloc = 100;
  path = bfd_malloc (alloc);
  if (path == NULL)
    return return_value;

  s = path;

  while (1)
    {
      if (bfd_bread (s, 1, core_bfd) != 1)
	goto xcoff64_core_file_matches_executable_p_end_1;

      if (*s == '\0')
	break;
      ++s;
      if (s == path + alloc)
	{
	  char *n;

	  alloc *= 2;
	  n = bfd_realloc (path, alloc);
	  if (n == NULL)
	    goto xcoff64_core_file_matches_executable_p_end_1;

	  s = n + (path - s);
	  path = n;
	}
    }

  str1 = strrchr (path, '/');
  str2 = strrchr (exec_bfd->filename, '/');

  /* Step over character '/'.  */
  str1 = str1 != NULL ? str1 + 1 : path;
  str2 = str2 != NULL ? str2 + 1 : exec_bfd->filename;

  if (strcmp (str1, str2) == 0)
    return_value = TRUE;

 xcoff64_core_file_matches_executable_p_end_1:
  free (path);
  return return_value;
}
void
_bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
			 asection *sec, struct elf_reloc_cookie *cookie)
{
#define REQUIRE(COND)					\
  do							\
    if (!(COND))					\
      goto free_no_table;				\
  while (0)

  bfd_byte *ehbuf = NULL, *buf, *end;
  bfd_byte *last_fde;
  struct eh_cie_fde *this_inf;
  unsigned int hdr_length, hdr_id;
  unsigned int cie_count;
  struct cie *cie, *local_cies = NULL;
  struct elf_link_hash_table *htab;
  struct eh_frame_hdr_info *hdr_info;
  struct eh_frame_sec_info *sec_info = NULL;
  unsigned int ptr_size;
  unsigned int num_cies;
  unsigned int num_entries;
  elf_gc_mark_hook_fn gc_mark_hook;

  htab = elf_hash_table (info);
  hdr_info = &htab->eh_info;
  if (hdr_info->parsed_eh_frames)
    return;

  if (sec->size == 0)
    {
      /* This file does not contain .eh_frame information.  */
      return;
    }

  if (bfd_is_abs_section (sec->output_section))
    {
      /* At least one of the sections is being discarded from the
	 link, so we should just ignore them.  */
      return;
    }

  /* Read the frame unwind information from abfd.  */

  REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf));

  if (sec->size >= 4
      && bfd_get_32 (abfd, ehbuf) == 0
      && cookie->rel == cookie->relend)
    {
      /* Empty .eh_frame section.  */
      free (ehbuf);
      return;
    }

  /* If .eh_frame section size doesn't fit into int, we cannot handle
     it (it would need to use 64-bit .eh_frame format anyway).  */
  REQUIRE (sec->size == (unsigned int) sec->size);

  ptr_size = (get_elf_backend_data (abfd)
	      ->elf_backend_eh_frame_address_size (abfd, sec));
  REQUIRE (ptr_size != 0);

  /* Go through the section contents and work out how many FDEs and
     CIEs there are.  */
  buf = ehbuf;
  end = ehbuf + sec->size;
  num_cies = 0;
  num_entries = 0;
  while (buf != end)
    {
      num_entries++;

      /* Read the length of the entry.  */
      REQUIRE (skip_bytes (&buf, end, 4));
      hdr_length = bfd_get_32 (abfd, buf - 4);

      /* 64-bit .eh_frame is not supported.  */
      REQUIRE (hdr_length != 0xffffffff);
      if (hdr_length == 0)
	break;

      REQUIRE (skip_bytes (&buf, end, 4));
      hdr_id = bfd_get_32 (abfd, buf - 4);
      if (hdr_id == 0)
	num_cies++;

      REQUIRE (skip_bytes (&buf, end, hdr_length - 4));
    }

  sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info)
			  + (num_entries - 1) * sizeof (struct eh_cie_fde));
  REQUIRE (sec_info);

  /* We need to have a "struct cie" for each CIE in this section.  */
  local_cies = bfd_zmalloc (num_cies * sizeof (*local_cies));
  REQUIRE (local_cies);

#define ENSURE_NO_RELOCS(buf)				\
  REQUIRE (!(cookie->rel < cookie->relend		\
	     && (cookie->rel->r_offset			\
		 < (bfd_size_type) ((buf) - ehbuf))	\
	     && cookie->rel->r_info != 0))

#define SKIP_RELOCS(buf)				\
  while (cookie->rel < cookie->relend			\
	 && (cookie->rel->r_offset			\
	     < (bfd_size_type) ((buf) - ehbuf)))	\
    cookie->rel++

#define GET_RELOC(buf)					\
  ((cookie->rel < cookie->relend			\
    && (cookie->rel->r_offset				\
	== (bfd_size_type) ((buf) - ehbuf)))		\
   ? cookie->rel : NULL)

  buf = ehbuf;
  cie_count = 0;
  gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook;
  while ((bfd_size_type) (buf - ehbuf) != sec->size)
    {
      char *aug;
      bfd_byte *start, *insns, *insns_end;
      bfd_size_type length;
      unsigned int set_loc_count;

      this_inf = sec_info->entry + sec_info->count;
      last_fde = buf;

      /* Read the length of the entry.  */
      REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4));
      hdr_length = bfd_get_32 (abfd, buf - 4);

      /* The CIE/FDE must be fully contained in this input section.  */
      REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size);
      end = buf + hdr_length;

      this_inf->offset = last_fde - ehbuf;
      this_inf->size = 4 + hdr_length;
      this_inf->reloc_index = cookie->rel - cookie->rels;

      if (hdr_length == 0)
	{
	  /* A zero-length CIE should only be found at the end of
	     the section.  */
	  REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size);
	  ENSURE_NO_RELOCS (buf);
	  sec_info->count++;
	  break;
	}

      REQUIRE (skip_bytes (&buf, end, 4));
      hdr_id = bfd_get_32 (abfd, buf - 4);

      if (hdr_id == 0)
	{
	  unsigned int initial_insn_length;

	  /* CIE  */
	  this_inf->cie = 1;

	  /* Point CIE to one of the section-local cie structures.  */
	  cie = local_cies + cie_count++;

	  cie->cie_inf = this_inf;
	  cie->length = hdr_length;
	  cie->output_sec = sec->output_section;
	  start = buf;
	  REQUIRE (read_byte (&buf, end, &cie->version));

	  /* Cannot handle unknown versions.  */
	  REQUIRE (cie->version == 1 || cie->version == 3);
	  REQUIRE (strlen ((char *) buf) < sizeof (cie->augmentation));

	  strcpy (cie->augmentation, (char *) buf);
	  buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1;
	  ENSURE_NO_RELOCS (buf);
	  if (buf[0] == 'e' && buf[1] == 'h')
	    {
	      /* GCC < 3.0 .eh_frame CIE */
	      /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__
		 is private to each CIE, so we don't need it for anything.
		 Just skip it.  */
	      REQUIRE (skip_bytes (&buf, end, ptr_size));
	      SKIP_RELOCS (buf);
	    }
	  REQUIRE (read_uleb128 (&buf, end, &cie->code_align));
	  REQUIRE (read_sleb128 (&buf, end, &cie->data_align));
	  if (cie->version == 1)
	    {
	      REQUIRE (buf < end);
	      cie->ra_column = *buf++;
	    }
	  else
	    REQUIRE (read_uleb128 (&buf, end, &cie->ra_column));
	  ENSURE_NO_RELOCS (buf);
	  cie->lsda_encoding = DW_EH_PE_omit;
	  cie->fde_encoding = DW_EH_PE_omit;
	  cie->per_encoding = DW_EH_PE_omit;
	  aug = cie->augmentation;
	  if (aug[0] != 'e' || aug[1] != 'h')
	    {
	      if (*aug == 'z')
		{
		  aug++;
		  REQUIRE (read_uleb128 (&buf, end, &cie->augmentation_size));
	  	  ENSURE_NO_RELOCS (buf);
		}

	      while (*aug != '\0')
		switch (*aug++)
		  {
		  case 'L':
		    REQUIRE (read_byte (&buf, end, &cie->lsda_encoding));
		    ENSURE_NO_RELOCS (buf);
		    REQUIRE (get_DW_EH_PE_width (cie->lsda_encoding, ptr_size));
		    break;
		  case 'R':
		    REQUIRE (read_byte (&buf, end, &cie->fde_encoding));
		    ENSURE_NO_RELOCS (buf);
		    REQUIRE (get_DW_EH_PE_width (cie->fde_encoding, ptr_size));
		    break;
		  case 'S':
		    break;
		  case 'P':
		    {
		      int per_width;

		      REQUIRE (read_byte (&buf, end, &cie->per_encoding));
		      per_width = get_DW_EH_PE_width (cie->per_encoding,
						      ptr_size);
		      REQUIRE (per_width);
		      if ((cie->per_encoding & 0xf0) == DW_EH_PE_aligned)
			{
			  length = -(buf - ehbuf) & (per_width - 1);
			  REQUIRE (skip_bytes (&buf, end, length));
			}
		      ENSURE_NO_RELOCS (buf);
		      /* Ensure we have a reloc here.  */
		      REQUIRE (GET_RELOC (buf));
		      cie->personality.reloc_index
			= cookie->rel - cookie->rels;
		      /* Cope with MIPS-style composite relocations.  */
		      do
			cookie->rel++;
		      while (GET_RELOC (buf) != NULL);
		      REQUIRE (skip_bytes (&buf, end, per_width));
		    }
		    break;
		  default:
		    /* Unrecognized augmentation. Better bail out.  */
		    goto free_no_table;
		  }
	    }

	  /* For shared libraries, try to get rid of as many RELATIVE relocs
	     as possible.  */
	  if (info->shared
	      && (get_elf_backend_data (abfd)
		  ->elf_backend_can_make_relative_eh_frame
		  (abfd, info, sec)))
	    {
	      if ((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr)
		this_inf->make_relative = 1;
	      /* If the CIE doesn't already have an 'R' entry, it's fairly
		 easy to add one, provided that there's no aligned data
		 after the augmentation string.  */
	      else if (cie->fde_encoding == DW_EH_PE_omit
		       && (cie->per_encoding & 0xf0) != DW_EH_PE_aligned)
		{
		  if (*cie->augmentation == 0)
		    this_inf->add_augmentation_size = 1;
		  this_inf->u.cie.add_fde_encoding = 1;
		  this_inf->make_relative = 1;
		}
	    }

	  if (info->shared
	      && (get_elf_backend_data (abfd)
		  ->elf_backend_can_make_lsda_relative_eh_frame
		  (abfd, info, sec))
	      && (cie->lsda_encoding & 0xf0) == DW_EH_PE_absptr)
	    cie->can_make_lsda_relative = 1;

	  /* If FDE encoding was not specified, it defaults to
	     DW_EH_absptr.  */
	  if (cie->fde_encoding == DW_EH_PE_omit)
	    cie->fde_encoding = DW_EH_PE_absptr;

	  initial_insn_length = end - buf;
	  if (initial_insn_length <= sizeof (cie->initial_instructions))
	    {
	      cie->initial_insn_length = initial_insn_length;
	      memcpy (cie->initial_instructions, buf, initial_insn_length);
	    }
	  insns = buf;
	  buf += initial_insn_length;
	  ENSURE_NO_RELOCS (buf);

	  if (hdr_info->merge_cies)
	    this_inf->u.cie.u.full_cie = cie;
	  this_inf->u.cie.per_encoding_relative
	    = (cie->per_encoding & 0x70) == DW_EH_PE_pcrel;
	}
      else
	{
	  asection *rsec;

	  /* Find the corresponding CIE.  */
	  unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
	  for (cie = local_cies; cie < local_cies + cie_count; cie++)
	    if (cie_offset == cie->cie_inf->offset)
	      break;

	  /* Ensure this FDE references one of the CIEs in this input
	     section.  */
	  REQUIRE (cie != local_cies + cie_count);
	  this_inf->u.fde.cie_inf = cie->cie_inf;
	  this_inf->make_relative = cie->cie_inf->make_relative;
	  this_inf->add_augmentation_size
	    = cie->cie_inf->add_augmentation_size;

	  ENSURE_NO_RELOCS (buf);
	  REQUIRE (GET_RELOC (buf));

	  /* Chain together the FDEs for each section.  */
	  rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
	  /* RSEC will be NULL if FDE was cleared out as it was belonging to
	     a discarded SHT_GROUP.  */
	  if (rsec)
	    {
	      REQUIRE (rsec->owner == abfd);
	      this_inf->u.fde.next_for_section = elf_fde_list (rsec);
	      elf_fde_list (rsec) = this_inf;
	    }

	  /* Skip the initial location and address range.  */
	  start = buf;
	  length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
	  REQUIRE (skip_bytes (&buf, end, 2 * length));

	  /* Skip the augmentation size, if present.  */
	  if (cie->augmentation[0] == 'z')
	    REQUIRE (read_uleb128 (&buf, end, &length));
	  else
	    length = 0;

	  /* Of the supported augmentation characters above, only 'L'
	     adds augmentation data to the FDE.  This code would need to
	     be adjusted if any future augmentations do the same thing.  */
	  if (cie->lsda_encoding != DW_EH_PE_omit)
	    {
	      SKIP_RELOCS (buf);
	      if (cie->can_make_lsda_relative && GET_RELOC (buf))
		cie->cie_inf->u.cie.make_lsda_relative = 1;
	      this_inf->lsda_offset = buf - start;
	      /* If there's no 'z' augmentation, we don't know where the
		 CFA insns begin.  Assume no padding.  */
	      if (cie->augmentation[0] != 'z')
		length = end - buf;
	    }

	  /* Skip over the augmentation data.  */
	  REQUIRE (skip_bytes (&buf, end, length));
	  insns = buf;

	  buf = last_fde + 4 + hdr_length;

	  /* For NULL RSEC (cleared FDE belonging to a discarded section)
	     the relocations are commonly cleared.  We do not sanity check if
	     all these relocations are cleared as (1) relocations to
	     .gcc_except_table will remain uncleared (they will get dropped
	     with the drop of this unused FDE) and (2) BFD already safely drops
	     relocations of any type to .eh_frame by
	     elf_section_ignore_discarded_relocs.
	     TODO: The .gcc_except_table entries should be also filtered as
	     .eh_frame entries; or GCC could rather use COMDAT for them.  */
	  SKIP_RELOCS (buf);
	}

      /* Try to interpret the CFA instructions and find the first
	 padding nop.  Shrink this_inf's size so that it doesn't
	 include the padding.  */
      length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
      set_loc_count = 0;
      insns_end = skip_non_nops (insns, end, length, &set_loc_count);
      /* If we don't understand the CFA instructions, we can't know
	 what needs to be adjusted there.  */
      if (insns_end == NULL
	  /* For the time being we don't support DW_CFA_set_loc in
	     CIE instructions.  */
	  || (set_loc_count && this_inf->cie))
	goto free_no_table;
      this_inf->size -= end - insns_end;
      if (insns_end != end && this_inf->cie)
	{
	  cie->initial_insn_length -= end - insns_end;
	  cie->length -= end - insns_end;
	}
      if (set_loc_count
	  && ((cie->fde_encoding & 0xf0) == DW_EH_PE_pcrel
	      || this_inf->make_relative))
	{
	  unsigned int cnt;
	  bfd_byte *p;

	  this_inf->set_loc = bfd_malloc ((set_loc_count + 1)
					  * sizeof (unsigned int));
	  REQUIRE (this_inf->set_loc);
	  this_inf->set_loc[0] = set_loc_count;
	  p = insns;
	  cnt = 0;
	  while (p < end)
	    {
	      if (*p == DW_CFA_set_loc)
		this_inf->set_loc[++cnt] = p + 1 - start;
	      REQUIRE (skip_cfa_op (&p, end, length));
	    }
	}

      this_inf->removed = 1;
      this_inf->fde_encoding = cie->fde_encoding;
      this_inf->lsda_encoding = cie->lsda_encoding;
      sec_info->count++;
    }
  BFD_ASSERT (sec_info->count == num_entries);
  BFD_ASSERT (cie_count == num_cies);

  elf_section_data (sec)->sec_info = sec_info;
  sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME;
  if (hdr_info->merge_cies)
    {
      sec_info->cies = local_cies;
      local_cies = NULL;
    }
  goto success;

 free_no_table:
  (*info->callbacks->einfo)
    (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"),
     abfd, sec);
  hdr_info->table = FALSE;
  if (sec_info)
    free (sec_info);
 success:
  if (ehbuf)
    free (ehbuf);
  if (local_cies)
    free (local_cies);
#undef REQUIRE
}
示例#27
0
文件: format.c 项目: DonCN/haiku
bfd_boolean
bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
{
  extern const bfd_target binary_vec;
  const bfd_target * const *target;
  const bfd_target **matching_vector = NULL;
  const bfd_target *save_targ, *right_targ, *ar_right_targ;
  int match_count;
  int ar_match_index;

  if (!bfd_read_p (abfd)
      || (unsigned int) abfd->format >= (unsigned int) bfd_type_end)
    {
      bfd_set_error (bfd_error_invalid_operation);
      return FALSE;
    }

  if (abfd->format != bfd_unknown)
    return abfd->format == format;

  /* Since the target type was defaulted, check them
     all in the hope that one will be uniquely recognized.  */
  save_targ = abfd->xvec;
  match_count = 0;
  ar_match_index = _bfd_target_vector_entries;

  if (matching)
    {
      bfd_size_type amt;

      *matching = NULL;
      amt = sizeof (*matching_vector) * 2 * _bfd_target_vector_entries;
      matching_vector = bfd_malloc (amt);
      if (!matching_vector)
	return FALSE;
    }

  right_targ = 0;
  ar_right_targ = 0;

  /* Presume the answer is yes.  */
  abfd->format = format;

  /* If the target type was explicitly specified, just check that target.  */
  if (!abfd->target_defaulted)
    {
      if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)	/* rewind! */
	{
	  if (matching)
	    free (matching_vector);
	  return FALSE;
	}

      right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));

      if (right_targ)
	{
	  abfd->xvec = right_targ;	/* Set the target as returned.  */

	  if (matching)
	    free (matching_vector);

	  return TRUE;			/* File position has moved, BTW.  */
	}

      /* For a long time the code has dropped through to check all
	 targets if the specified target was wrong.  I don't know why,
	 and I'm reluctant to change it.  However, in the case of an
	 archive, it can cause problems.  If the specified target does
	 not permit archives (e.g., the binary target), then we should
	 not allow some other target to recognize it as an archive, but
	 should instead allow the specified target to recognize it as an
	 object.  When I first made this change, it broke the PE target,
	 because the specified pei-i386 target did not recognize the
	 actual pe-i386 archive.  Since there may be other problems of
	 this sort, I changed this test to check only for the binary
	 target.  */
      if (format == bfd_archive && save_targ == &binary_vec)
	{
	  abfd->xvec = save_targ;
	  abfd->format = bfd_unknown;

	  if (matching)
	    free (matching_vector);

	  bfd_set_error (bfd_error_file_not_recognized);

	  return FALSE;
	}
    }

  for (target = bfd_target_vector; *target != NULL; target++)
    {
      const bfd_target *temp;
      bfd_error_type err;

      if (*target == &binary_vec)
	continue;

      abfd->xvec = *target;	/* Change BFD's target temporarily.  */

      if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
	{
	  if (matching)
	    free (matching_vector);
	  return FALSE;
	}

      /* If _bfd_check_format neglects to set bfd_error, assume
	 bfd_error_wrong_format.  We didn't used to even pay any
	 attention to bfd_error, so I suspect that some
	 _bfd_check_format might have this problem.  */
      bfd_set_error (bfd_error_wrong_format);

      temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));

      if (temp)
	{
	  /* This format checks out as ok!  */
	  right_targ = temp;

	  /* If this is the default target, accept it, even if other
	     targets might match.  People who want those other targets
	     have to set the GNUTARGET variable.  */
	  if (temp == bfd_default_vector[0])
	    {
	      match_count = 1;
	      break;
	    }

	  if (matching)
	    matching_vector[match_count] = temp;

	  match_count++;

#ifdef GNU960
	  /* Big- and little-endian b.out archives look the same, but it
	     doesn't matter: there is no difference in their headers, and
	     member file byte orders will (I hope) be handled appropriately
	     by bfd.  Ditto for big and little coff archives.  And the 4
	     coff/b.out object formats are unambiguous.  So accept the
	     first match we find.  */
	  break;
#endif
	}
      else if ((err = bfd_get_error ()) == bfd_error_wrong_object_format
	       || err == bfd_error_file_ambiguously_recognized)
	{
	  /* An archive with objects of the wrong type, or an
	     ambiguous match.  We want this target to match if we get
	     no better matches.  */
	  if (ar_right_targ != bfd_default_vector[0])
	    ar_right_targ = *target;
	  if (matching)
	    matching_vector[ar_match_index] = *target;
	  ar_match_index++;
	}
      else if (err != bfd_error_wrong_format)
	{
	  abfd->xvec = save_targ;
	  abfd->format = bfd_unknown;

	  if (matching)
	    free (matching_vector);

	  return FALSE;
	}
    }

  if (match_count == 0)
    {
      /* Try partial matches.  */
      right_targ = ar_right_targ;

      if (right_targ == bfd_default_vector[0])
	{
	  match_count = 1;
	}
      else
	{
	  match_count = ar_match_index - _bfd_target_vector_entries;

	  if (matching && match_count > 1)
	    memcpy (matching_vector,
		    matching_vector + _bfd_target_vector_entries,
		    sizeof (*matching_vector) * match_count);
	}
    }

  if (match_count > 1
      && bfd_associated_vector != NULL
      && matching)
    {
      const bfd_target * const *assoc = bfd_associated_vector;

      while ((right_targ = *assoc++) != NULL)
	{
	  int i = match_count;

	  while (--i >= 0)
	    if (matching_vector[i] == right_targ)
	      break;

	  if (i >= 0)
	    {
	      match_count = 1;
	      break;
	    }
	}
    }

  if (match_count == 1)
    {
      abfd->xvec = right_targ;		/* Change BFD's target permanently.  */

      if (matching)
	free (matching_vector);

      return TRUE;			/* File position has moved, BTW.  */
    }

  abfd->xvec = save_targ;		/* Restore original target type.  */
  abfd->format = bfd_unknown;		/* Restore original format.  */

  if (match_count == 0)
    {
      bfd_set_error (bfd_error_file_not_recognized);

      if (matching)
	free (matching_vector);
    }
  else
    {
      bfd_set_error (bfd_error_file_ambiguously_recognized);

      if (matching)
	{
	  *matching = (char **) matching_vector;
	  matching_vector[match_count] = NULL;
	  /* Return target names.  This is a little nasty.  Maybe we
	     should do another bfd_malloc?  */
	  while (--match_count >= 0)
	    {
	      const char *name = matching_vector[match_count]->name;
	      *(const char **) &matching_vector[match_count] = name;
	    }
	}
    }

  return FALSE;
}
示例#28
0
static bfd_boolean
sh64_address_in_cranges (asection *cranges, bfd_vma addr,
                         sh64_elf_crange *rangep)
{
    bfd_byte *cranges_contents;
    bfd_byte *found_rangep;
    bfd_size_type cranges_size = bfd_section_size (cranges->owner, cranges);

    /* If the size is not a multiple of the cranges entry size, then
       something is badly wrong.  */
    if ((cranges_size % SH64_CRANGE_SIZE) != 0)
        return FALSE;

    /* If this section has relocations, then we can't do anything sane.  */
    if (bfd_get_section_flags (cranges->owner, cranges) & SEC_RELOC)
        return FALSE;

    /* Has some kind soul (or previous call) left processed, sorted contents
       for us?  */
    if ((bfd_get_section_flags (cranges->owner, cranges) & SEC_IN_MEMORY)
            && elf_section_data (cranges)->this_hdr.sh_type == SHT_SH5_CR_SORTED)
        cranges_contents = cranges->contents;
    else
    {
        cranges_contents
            = bfd_malloc (cranges->_cooked_size != 0
                          ? cranges->_cooked_size : cranges->_raw_size);
        if (cranges_contents == NULL)
            return FALSE;

        if (! bfd_get_section_contents (cranges->owner, cranges,
                                        cranges_contents, (file_ptr) 0,
                                        cranges_size))
            goto error_return;

        /* Is it sorted?  */
        if (elf_section_data (cranges)->this_hdr.sh_type
                != SHT_SH5_CR_SORTED)
            /* Nope.  Lets sort it.  */
            qsort (cranges_contents, cranges_size / SH64_CRANGE_SIZE,
                   SH64_CRANGE_SIZE,
                   bfd_big_endian (cranges->owner)
                   ? _bfd_sh64_crange_qsort_cmpb : _bfd_sh64_crange_qsort_cmpl);

        /* Let's keep it around.  */
        cranges->contents = cranges_contents;
        bfd_set_section_flags (cranges->owner, cranges,
                               bfd_get_section_flags (cranges->owner, cranges)
                               | SEC_IN_MEMORY);

        /* It's sorted now.  */
        elf_section_data (cranges)->this_hdr.sh_type = SHT_SH5_CR_SORTED;
    }

    /* Try and find a matching range.  */
    found_rangep
        = bsearch (&addr, cranges_contents, cranges_size / SH64_CRANGE_SIZE,
                   SH64_CRANGE_SIZE,
                   bfd_big_endian (cranges->owner)
                   ? _bfd_sh64_crange_bsearch_cmpb
                   : _bfd_sh64_crange_bsearch_cmpl);

    /* Fill in a few return values if we found a matching range.  */
    if (found_rangep)
    {
        enum sh64_elf_cr_type cr_type
            = bfd_get_16 (cranges->owner,
                          SH64_CRANGE_CR_TYPE_OFFSET + found_rangep);
        bfd_vma cr_addr
            = bfd_get_32 (cranges->owner,
                          SH64_CRANGE_CR_ADDR_OFFSET
                          + (char *) found_rangep);
        bfd_size_type cr_size
            = bfd_get_32 (cranges->owner,
                          SH64_CRANGE_CR_SIZE_OFFSET
                          + (char *) found_rangep);

        rangep->cr_addr = cr_addr;
        rangep->cr_size = cr_size;
        rangep->cr_type = cr_type;

        return TRUE;
    }

    /* There is a .cranges section, but it does not have a descriptor
       matching this address.  */
    return FALSE;

error_return:
    free (cranges_contents);
    return FALSE;
}
示例#29
0
static bfd_boolean
sh_symbian_import_as (struct bfd_link_info *info, bfd * abfd,
		      char * current_name, char * new_name)
{
  struct elf_link_hash_entry * new_hash;
  symbol_rename * node;

  if (SYMBIAN_DEBUG)
    fprintf (stderr, "IMPORT '%s' AS '%s'\n", current_name, new_name);

  for (node = rename_list; node; node = node->next)
    if (strcmp (node->current_name, current_name) == 0)
      {
	if (strcmp (node->new_name, new_name) == 0)
	  /* Already added to rename list.  */
	  return TRUE;

	bfd_set_error (bfd_error_invalid_operation);
	_bfd_error_handler (_("%B: IMPORT AS directive for %s conceals previous IMPORT AS"),
			    abfd, current_name);
	return FALSE;	    
      }

  if ((node = bfd_malloc (sizeof * node)) == NULL)
    {
      if (SYMBIAN_DEBUG)
	fprintf (stderr, "IMPORT AS: No mem for new rename node\n");
      return FALSE;
    }

  if ((node->current_name = bfd_malloc (strlen (current_name) + 1)) == NULL)
    {
      if (SYMBIAN_DEBUG)
	fprintf (stderr, "IMPORT AS: No mem for current name field in rename node\n");
      free (node);
      return FALSE;
    }
  else
    strcpy (node->current_name, current_name);
  
  if ((node->new_name = bfd_malloc (strlen (new_name) + 1)) == NULL)
    {
      if (SYMBIAN_DEBUG)
	fprintf (stderr, "IMPORT AS: No mem for new name field in rename node\n");
      free (node->current_name);
      free (node);
      return FALSE;
    }
  else
    strcpy (node->new_name, new_name);

  node->next = rename_list;
  node->current_hash = NULL;
  node->new_symndx = 0;
  rename_list = node;

  new_hash = elf_link_hash_lookup (elf_hash_table (info), node->new_name, TRUE, FALSE, TRUE);
  bfd_elf_link_record_dynamic_symbol (info, new_hash);
  if (new_hash->root.type == bfd_link_hash_new)
    new_hash->root.type = bfd_link_hash_undefined;

  return TRUE;
}
示例#30
0
bfd_boolean
bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
{
  bfd_size_type sz;
  bfd_byte *p = *ptr;
  bfd_boolean ret;
  bfd_size_type save_size;
  bfd_size_type save_rawsize;
  bfd_byte *compressed_buffer;
  unsigned int compression_header_size;

  if (abfd->direction != write_direction && sec->rawsize != 0)
    sz = sec->rawsize;
  else
    sz = sec->size;
  if (sz == 0)
    {
      *ptr = NULL;
      return TRUE;
    }

  switch (sec->compress_status)
    {
    case COMPRESS_SECTION_NONE:
      if (p == NULL)
	{
	  p = (bfd_byte *) bfd_malloc (sz);
	  if (p == NULL)
	    return FALSE;
	}

      if (!bfd_get_section_contents (abfd, sec, p, 0, sz))
	{
	  if (*ptr != p)
	    free (p);
	  return FALSE;
	}
      *ptr = p;
      return TRUE;

    case DECOMPRESS_SECTION_SIZED:
      /* Read in the full compressed section contents.  */
      compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size);
      if (compressed_buffer == NULL)
	return FALSE;
      save_rawsize = sec->rawsize;
      save_size = sec->size;
      /* Clear rawsize, set size to compressed size and set compress_status
	 to COMPRESS_SECTION_NONE.  If the compressed size is bigger than
	 the uncompressed size, bfd_get_section_contents will fail.  */
      sec->rawsize = 0;
      sec->size = sec->compressed_size;
      sec->compress_status = COMPRESS_SECTION_NONE;
      ret = bfd_get_section_contents (abfd, sec, compressed_buffer,
				      0, sec->compressed_size);
      /* Restore rawsize and size.  */
      sec->rawsize = save_rawsize;
      sec->size = save_size;
      sec->compress_status = DECOMPRESS_SECTION_SIZED;
      if (!ret)
	goto fail_compressed;

      if (p == NULL)
	p = (bfd_byte *) bfd_malloc (sz);
      if (p == NULL)
	goto fail_compressed;

      compression_header_size = bfd_get_compression_header_size (abfd, sec);
      if (!decompress_contents (compressed_buffer + compression_header_size,
				sec->compressed_size, p, sz))
	{
	  bfd_set_error (bfd_error_bad_value);
	  if (p != *ptr)
	    free (p);
	fail_compressed:
	  free (compressed_buffer);
	  return FALSE;
	}

      free (compressed_buffer);
      *ptr = p;
      return TRUE;

    case COMPRESS_SECTION_DONE:
      if (sec->contents == NULL)
	return FALSE;
      if (p == NULL)
	{
	  p = (bfd_byte *) bfd_malloc (sz);
	  if (p == NULL)
	    return FALSE;
	  *ptr = p;
	}
      /* PR 17512; file: 5bc29788.  */
      if (p != sec->contents)
	memcpy (p, sec->contents, sz);
      return TRUE;

    default:
      abort ();
    }
}