mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-11-03 20:53:13 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			235 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright (C) 1999, 2000, 2001, 2002, 2007 Free Software Foundation, Inc.
 | 
						|
   This file is part of the GNU C Library.
 | 
						|
   Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
 | 
						|
		  Jakub Jelinek <jakub@redhat.com>, 1999.
 | 
						|
 | 
						|
   The GNU C Library is free software; you can redistribute it and/or
 | 
						|
   modify it under the terms of the GNU Lesser General Public
 | 
						|
   License as published by the Free Software Foundation; either
 | 
						|
   version 2.1 of the License, or (at your option) any later version.
 | 
						|
 | 
						|
   The GNU C Library 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
 | 
						|
   Lesser General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU Lesser General Public
 | 
						|
   License along with the GNU C Library; if not, see
 | 
						|
   <http://www.gnu.org/licenses/>.  */
 | 
						|
 | 
						|
/* This code is a heavily simplified version of the readelf program
 | 
						|
   that's part of the current binutils development version.  For architectures
 | 
						|
   which need to handle both 32bit and 64bit ELF libraries,  this file is
 | 
						|
   included twice for each arch size.  */
 | 
						|
 | 
						|
/* check_ptr checks that a pointer is in the mmaped file and doesn't
 | 
						|
   point outside it.  */
 | 
						|
#undef check_ptr
 | 
						|
#define check_ptr(ptr)						\
 | 
						|
do								\
 | 
						|
  {								\
 | 
						|
    if ((void *)(ptr) < file_contents				\
 | 
						|
	|| (void *)(ptr) > (file_contents+file_length))		\
 | 
						|
      {								\
 | 
						|
	error (0, 0, _("file %s is truncated\n"), file_name);	\
 | 
						|
	return 1;						\
 | 
						|
      }								\
 | 
						|
  }								\
 | 
						|
 while (0);
 | 
						|
 | 
						|
/* Returns 0 if everything is ok, != 0 in case of error.  */
 | 
						|
int
 | 
						|
process_elf_file (const char *file_name, const char *lib, int *flag,
 | 
						|
		  unsigned int *osversion, char **soname, void *file_contents,
 | 
						|
		  size_t file_length)
 | 
						|
{
 | 
						|
  int i;
 | 
						|
  unsigned int j;
 | 
						|
  ElfW(Addr) loadaddr;
 | 
						|
  unsigned int dynamic_addr;
 | 
						|
  size_t dynamic_size;
 | 
						|
  char *program_interpreter;
 | 
						|
 | 
						|
  ElfW(Ehdr) *elf_header;
 | 
						|
  ElfW(Phdr) *elf_pheader, *segment;
 | 
						|
  ElfW(Dyn) *dynamic_segment, *dyn_entry;
 | 
						|
  char *dynamic_strings;
 | 
						|
 | 
						|
  elf_header = (ElfW(Ehdr) *) file_contents;
 | 
						|
  *osversion = 0;
 | 
						|
 | 
						|
  if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS))
 | 
						|
    {
 | 
						|
      if (opt_verbose)
 | 
						|
	{
 | 
						|
	  if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
 | 
						|
	    error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name);
 | 
						|
	  else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64)
 | 
						|
	    error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name);
 | 
						|
	  else
 | 
						|
	    error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name);
 | 
						|
	}
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
  if (elf_header->e_type != ET_DYN)
 | 
						|
    {
 | 
						|
      error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
 | 
						|
	     elf_header->e_type);
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Get information from elf program header.  */
 | 
						|
  elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
 | 
						|
  check_ptr (elf_pheader);
 | 
						|
 | 
						|
  /* The library is an elf library, now search for soname and
 | 
						|
     libc5/libc6.  */
 | 
						|
  *flag = FLAG_ELF;
 | 
						|
 | 
						|
  loadaddr = -1;
 | 
						|
  dynamic_addr = 0;
 | 
						|
  dynamic_size = 0;
 | 
						|
  program_interpreter = NULL;
 | 
						|
  for (i = 0, segment = elf_pheader;
 | 
						|
       i < elf_header->e_phnum; i++, segment++)
 | 
						|
    {
 | 
						|
      check_ptr (segment);
 | 
						|
 | 
						|
      switch (segment->p_type)
 | 
						|
	{
 | 
						|
	case PT_LOAD:
 | 
						|
	  if (loadaddr == (ElfW(Addr)) -1)
 | 
						|
	    loadaddr = segment->p_vaddr - segment->p_offset;
 | 
						|
	  break;
 | 
						|
 | 
						|
	case PT_DYNAMIC:
 | 
						|
	  if (dynamic_addr)
 | 
						|
	    error (0, 0, _("more than one dynamic segment\n"));
 | 
						|
 | 
						|
	  dynamic_addr = segment->p_offset;
 | 
						|
	  dynamic_size = segment->p_filesz;
 | 
						|
	  break;
 | 
						|
 | 
						|
	case PT_INTERP:
 | 
						|
	  program_interpreter = (char *) (file_contents + segment->p_offset);
 | 
						|
	  check_ptr (program_interpreter);
 | 
						|
 | 
						|
	  /* Check if this is enough to classify the binary.  */
 | 
						|
	  for (j = 0; j < sizeof (interpreters) / sizeof (interpreters [0]);
 | 
						|
	       ++j)
 | 
						|
	    if (strcmp (program_interpreter, interpreters[j].soname) == 0)
 | 
						|
	      {
 | 
						|
		*flag = interpreters[j].flag;
 | 
						|
		break;
 | 
						|
	      }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case PT_NOTE:
 | 
						|
	  if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4)
 | 
						|
	    {
 | 
						|
	      ElfW(Word) *abi_note = (ElfW(Word) *) (file_contents
 | 
						|
						     + segment->p_offset);
 | 
						|
	      ElfW(Addr) size = segment->p_filesz;
 | 
						|
 | 
						|
	      while (abi_note [0] != 4 || abi_note [1] != 16
 | 
						|
		     || abi_note [2] != 1
 | 
						|
		     || memcmp (abi_note + 3, "GNU", 4) != 0)
 | 
						|
		{
 | 
						|
#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
 | 
						|
		  ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
 | 
						|
					 + ROUND (abi_note[0])
 | 
						|
					 + ROUND (abi_note[1]);
 | 
						|
 | 
						|
		  if (size - 32 < note_size || note_size == 0)
 | 
						|
		    {
 | 
						|
		      size = 0;
 | 
						|
		      break;
 | 
						|
		    }
 | 
						|
		  size -= note_size;
 | 
						|
		  abi_note = (void *) abi_note + note_size;
 | 
						|
		}
 | 
						|
 | 
						|
	      if (size == 0)
 | 
						|
		break;
 | 
						|
 | 
						|
	      *osversion = (abi_note [4] << 24) |
 | 
						|
			   ((abi_note [5] & 0xff) << 16) |
 | 
						|
			   ((abi_note [6] & 0xff) << 8) |
 | 
						|
			   (abi_note [7] & 0xff);
 | 
						|
	    }
 | 
						|
	  break;
 | 
						|
 | 
						|
	default:
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
    }
 | 
						|
  if (loadaddr == (ElfW(Addr)) -1)
 | 
						|
    {
 | 
						|
      /* Very strange. */
 | 
						|
      loadaddr = 0;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Now we can read the dynamic sections.  */
 | 
						|
  if (dynamic_size == 0)
 | 
						|
    return 1;
 | 
						|
 | 
						|
  dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
 | 
						|
  check_ptr (dynamic_segment);
 | 
						|
 | 
						|
  /* Find the string table.  */
 | 
						|
  dynamic_strings = NULL;
 | 
						|
  for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
 | 
						|
       ++dyn_entry)
 | 
						|
    {
 | 
						|
      check_ptr (dyn_entry);
 | 
						|
      if (dyn_entry->d_tag == DT_STRTAB)
 | 
						|
	{
 | 
						|
	  dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
 | 
						|
	  check_ptr (dynamic_strings);
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  if (dynamic_strings == NULL)
 | 
						|
    return 1;
 | 
						|
 | 
						|
  /* Now read the DT_NEEDED and DT_SONAME entries.  */
 | 
						|
  for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
 | 
						|
       ++dyn_entry)
 | 
						|
    {
 | 
						|
      if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME)
 | 
						|
	{
 | 
						|
	  char *name = dynamic_strings + dyn_entry->d_un.d_val;
 | 
						|
	  check_ptr (name);
 | 
						|
 | 
						|
	  if (dyn_entry->d_tag == DT_NEEDED)
 | 
						|
	    {
 | 
						|
 | 
						|
	      if (*flag == FLAG_ELF)
 | 
						|
		{
 | 
						|
		  /* Check if this is enough to classify the binary.  */
 | 
						|
		  for (j = 0;
 | 
						|
		       j < sizeof (known_libs) / sizeof (known_libs [0]);
 | 
						|
		       ++j)
 | 
						|
		    if (strcmp (name, known_libs [j].soname) == 0)
 | 
						|
		      {
 | 
						|
			*flag = known_libs [j].flag;
 | 
						|
			break;
 | 
						|
		      }
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	  else if (dyn_entry->d_tag == DT_SONAME)
 | 
						|
	    *soname = xstrdup (name);
 | 
						|
 | 
						|
	  /* Do we have everything we need?  */
 | 
						|
	  if (*soname && *flag != FLAG_ELF)
 | 
						|
	    return 0;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 |