/*
** dynsym.c for libelfsh
** 
** Started on  Mon Feb 26 04:13:29 2001 mayhem
** Last update Sun Mar 10 23:24:30 2002 mayhem
*/
#include "libelfsh.h"





/* Return the dynsymbol name giving its index in the dynamic symbol string table */
char	*elfsh_get_dynsymbol_name(Elfsh32_Obj *file, Elf32_Sym *s)
{
  Elf32_Shdr	*sct;

  if (file->dynsym == NULL && elfsh_get_dynsymtab(file, NULL) == NULL)
    return (NULL);

  /* Use the section string table if the symbol is a section */
  if (elfsh_get_symbol_type(s) == STT_SECTION)
    {
      sct = elfsh_get_shtentry_from_sym(file, s);
      return (sct ? elfsh_get_section_name(file, sct) : NULL);
    }

  return ((char *) file->dyn_strtab->data + s->st_name);
}






/* Return a ptr on the dynamic symbol table num is filled with the entries total number */
void		*elfsh_get_dynsymtab(Elfsh32_Obj *file, int *num)
{
  Elfsh32_Sect	*new;
  int		strindex;
  int		nbr;

  if (!file->dynsym)
    {

      /* Load the .dynsym */
      new = elfsh_get_section_by_type(file, SHT_DYNSYM, NULL, &strindex, &nbr, 0);
      if (!new)
	return (NULL);

      new->nbr = nbr / ELFSH_SYMTAB_ENTRY_SIZE;
      
      new->data = elfsh_load_section(file, new->shdr);
      if (!new->data) 
	return (NULL);
      
      file->dynsym = new;

      /* Now retreive the dynamic symbol string table .dynstr */
      new = elfsh_get_section_by_index(file, strindex, NULL, &nbr);
      if (!new)
	return (NULL);

      new->data = elfsh_load_section(file, new->shdr);
      if (!new->data)
	return (NULL);

      new->nbr = nbr;
      file->dyn_strtab = new;

    }

  if (num)
    *num = file->dynsym->nbr;

  return (file->dynsym->data);

}







/* Return the dynamic symbol name giving its value */
char		*elfsh_reverse_dynsymbol(Elfsh32_Obj *file, u_int value, int *offset)
{
  Elf32_Sym	*sorted;
  int		num;
  int		index;
  char		*str;

  if (value == 0 || value == 0xFFFFFFFF)
    return (NULL);  
  if (!file->dynsym && !elfsh_get_dynsymtab(file, &num))
    return (NULL);

  sorted = elfsh_copy_symtab(file->dynsym->data, num);
  if (!sorted || elfsh_sort_symtab(sorted, num, ELFSH_SORT_BY_ADDR) < 0)
    return (NULL);
  
  for (index = 0; index < num; index++)
    if (sorted[index].st_value >= (u_int) value)
      {
	if (!index)
	  {
	    str = NULL;
	    break;
	  }
	*offset = (int) value - sorted[index - 1].st_value;
	str = elfsh_get_dynsymbol_name(file, sorted + index - 1);
	break;
      }

  free(sorted);
  return (str);

}





/* Return the symbol entry giving its name */
Elf32_Sym	*elfsh_get_dynsymbol_by_name(Elfsh32_Obj *file, char *name)
{
  Elf32_Sym	*ret;
  int		index;
  int		size = 0;
  char		*actual;

  if (!elfsh_get_dynsymtab(file, &size))
    return (NULL);
  if (!name)
    return (NULL);

  ret = file->dynsym->data;
  for (index = 0; index < size; index++)
    {
      actual = elfsh_get_dynsymbol_name(file, ret + index);
      if (actual && !strcmp(actual, name))
	return (ret + index);
    }
  
  ELFSH_SETERROR("ELFshlib: symbol not found .", NULL);
}


























