All pastes #1227041 Raw Edit

Miscellany

public text v1 · immutable
#1227041 ·published 2008-10-14 17:53 UTC
rendered paste body
/**
 * @file dynsym.c
 * @ingroup libelfsh
** Dynsym.c for libelfsh
** 
** Started on  Mon Feb 26 04:13:29 2001 jfv
** 
**
** $Id: dynsym.c,v 1.21 2008-02-16 12:32:27 thor Exp $
**
*/
#include "libelfsh.h"


/**
 * Return the dynsymbol name giving its index in the dynamic symbol string table 
 * @param file
 * @param s
 * @return
 */
char		*elfsh_get_dynsymbol_name(elfshobj_t *file, elfsh_Sym *s)
{
  char	*ret;
  void	*rdata;

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);

  if (!file || !s)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		 "Invalid NULL parameter", NULL);
  
  if (file->secthash[ELFSH_SECTION_DYNSYM] == NULL)
    if (NULL == elfsh_get_dynsymtab(file, NULL))
      PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		   "Unable to get DYNSYM", NULL);
  
  rdata = elfsh_get_raw(file->secthash[ELFSH_SECTION_DYNSTR]);
  ret = (char *) rdata + s->st_name;


  fprintf(stderr, "Sending: %p - value: %s\n", ret, ret);
  fflush(stderr);

  
  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, ret);
}



/**
 * Return the used offset in .dynstr or -1 if failed 
 * @param file
 * @param s
 * @param name
 * @return
 */
int		elfsh_set_dynsymbol_name(elfshobj_t *file, 
					 elfsh_Sym *s, char *name)
{
  char		*str;
  u_int		len;
  u_int		new_len;
  void		*data;

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);

  if (file == NULL || s == NULL || name == NULL)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		      "Invalid NULL parameter", -1);

  if (file->secthash[ELFSH_SECTION_DYNSYM] == NULL && 
      elfsh_get_dynsymtab(file, NULL) == NULL)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		      "Cannot retreive symbol table", -1);

  /* Else use the symbol string table */
  data = elfsh_get_raw(file->secthash[ELFSH_SECTION_DYNSTR]);
  if (file->secthash[ELFSH_SECTION_DYNSTR] == NULL || 
      data == NULL)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		      "Unable to get DYNSTR", NULL);

  /* Change the name */
  str = (char *) file->secthash[ELFSH_SECTION_DYNSTR]->data;
  str += s->st_name;
  len = strlen(str);
  new_len = strlen(name);

  /* Do not allocate new place if possible */
  if (len >= new_len)
    strncpy(str, name, new_len);
  /* Append the name to .strtab */
  else
    s->st_name = elfsh_insert_in_dynstr(file, name);

  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (s->st_name));
}






/**
 * Return a ptr on the dynamic symbol table num is filled with the entries total number 
 * @param file
 * @param num
 * @return
 */
void		*elfsh_get_dynsymtab(elfshobj_t *file, int *num)
{
  elfshsect_t	*newent;
  int		strindex;
  int		nbr;
  void		*ret;

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);

  if (file == NULL)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		      "Invalid NULL parameter", NULL);

  //fprintf(stderr, "Calling get_dynsymtab ! \n");

  /* Load the .dynsym */
  if (file->secthash[ELFSH_SECTION_DYNSYM] == NULL)
    {
      newent = elfsh_get_section_by_name(file, 
					 ELFSH_SECTION_NAME_ALTDYNSYM, 
					 NULL, &strindex, &nbr);
      if (newent == NULL)
	{
	  newent = elfsh_get_section_by_type(file, SHT_DYNSYM, 0,
					     NULL, &strindex, &nbr);
	  if (newent == NULL)
	    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
			      "Unable to get DYNSYM by type", NULL);
	}

      newent->data = elfsh_load_section(file, newent->shdr);
      if (newent->data == NULL) 
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
			  "Unable to load DYNSYM", NULL);
      file->secthash[ELFSH_SECTION_DYNSYM] = newent;
      
      /* Endianize table */
      elfsh_endianize_symtab(newent); 
      
      /* Now retreive the dynamic symbol string table .dynstr */
      newent = elfsh_get_section_by_index(file, strindex, NULL, &nbr);
      if (newent == NULL)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
			  "Unable to get DYNSTR by index", NULL);

      newent->data = elfsh_load_section(file, newent->shdr);
      if (newent->data == NULL)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
			  "Unable to load DYNSTR", NULL);

      file->secthash[ELFSH_SECTION_DYNSTR] = newent;

      /* Fixup the dynamic symbol table */
      elfsh_fixup_dynsymtab(file->secthash[ELFSH_SECTION_DYNSYM]);

      /* Sort the table */
      elfsh_sync_sorted_symtab(file->secthash[ELFSH_SECTION_DYNSYM]);
      newent->curend = newent->shdr->sh_size;
    }

  /*
  fprintf(stderr, "dynsym curend = %u (%u entries) shsize = %u (%u entries) \n", 
	  file->secthash[ELFSH_SECTION_DYNSYM]->curend,
	  file->secthash[ELFSH_SECTION_DYNSYM]->curend / sizeof(elfsh_Sym),
	  file->secthash[ELFSH_SECTION_DYNSYM]->shdr->sh_size,
	  file->secthash[ELFSH_SECTION_DYNSYM]->shdr->sh_size / sizeof(elfsh_Sym));
  */

  nbr = 
    file->secthash[ELFSH_SECTION_DYNSYM]->curend ? 
    file->secthash[ELFSH_SECTION_DYNSYM]->curend / sizeof(elfsh_Sym) : 
    file->secthash[ELFSH_SECTION_DYNSYM]->shdr->sh_size / sizeof(elfsh_Sym);
    
  if (num != NULL)
    *num = nbr;

  ret = elfsh_get_raw(file->secthash[ELFSH_SECTION_DYNSYM]);
  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, ret);
}


/**
 * Get symtab entry by vaddr 
 * @param file
 * @param vaddr
 * @param off
 * @param mode
 * @return
 */
elfsh_Sym	  *elfsh_get_dynsymbol_by_value(elfshobj_t	*file,
						eresi_Addr	vaddr,
						int	*off,
						int	mode)
{
  int		  num;
  elfsh_Sym	  *data;

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);

  data = elfsh_get_dynsymtab(file, &num);
  if (data == NULL)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		      "Cannot retreive DYNSYM", NULL);

  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 
		     (elfsh_get_sym_by_value(data, num, vaddr, off, mode)));
}


/** 
 * Return the dynamic symbol name giving its value, 
 * Fill 'offset' with the difference between sym->st_value and 'value'
 *
 * @param file
 * @param value
 * @param offset
 * @return
 */
char		*elfsh_reverse_dynsymbol(elfshobj_t	*file,
					 eresi_Addr	value, 
					 elfsh_SAddr    *offset)
{
  elfshsect_t	*sect;
  elfsh_Sym	*sorted;
  int		num;
  int		index;
  char		*str;
  elfsh_Sym	*pltsym;
  elfshsect_t	*plt;
  

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);

  /* Sanity checks */
  if (!value || value == (eresi_Addr) -1)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		      "Invalid parameters", NULL);  
  if (file == NULL)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		      "Invalid NULL parameter", NULL);
  if (offset)
    *offset = 0;

  /* If there is no symtab, resolve using SHT */
  if (elfsh_get_dynsymtab(file, &num) == NULL) 
    {
      sect = elfsh_get_parent_section(file, value, offset);
      if (sect == NULL)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
			  "No parent section", NULL);

      /* handle dynamic case */
      if (elfsh_is_debug_mode())
	value -= file->rhdr.base;

      if (offset)
	*offset = (elfsh_SAddr) (sect->shdr->sh_addr - value);

      PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 
			 (elfsh_get_section_name(file, sect)));
    }

  /* Else use the sorted-by-address symbol table to match what we want */
  if (file->secthash[ELFSH_SECTION_DYNSYM]->altdata == NULL)
    elfsh_sync_sorted_symtab(file->secthash[ELFSH_SECTION_DYNSYM]);
  sorted = (elfsh_Sym *) file->secthash[ELFSH_SECTION_DYNSYM]->altdata;

  /* Restore dynsym if pointing inside PLT and we did not find it */ 
  plt = file->secthash[ELFSH_SECTION_PLT];
  sect = elfsh_get_parent_section(file, value, offset); 
  if (plt && sect && sect->name && !strcmp(sect->name, ELFSH_SECTION_NAME_PLT))
    {
      pltsym = elfsh_restore_dynsym(file, plt, *offset,
				    file->secthash[ELFSH_SECTION_DYNSYM]);
      if (pltsym)
	{
	  if (offset)
	    *offset = 0;
	  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__,
			     (elfsh_get_dynsymbol_name(file, pltsym)));
	}                                                                                                                                   
    }

  /* handle dynamic case */
  if (elfsh_is_debug_mode())
    value -= file->rhdr.base;

  /* Else look in the table */
  for (index = 0; index < num; index++)
    if (sorted[index].st_value <= value && DUMPABLE(sorted + index) &&
	(index + 1 >= num || sorted[index + 1].st_value > value))
      {
	
	if (offset)
	    *offset = (elfsh_SAddr) (value - sorted[index].st_value);
	str = elfsh_get_dynsymbol_name(file, sorted + index);
	if (!*str)
	  str = NULL;
	
	
	PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (str));
      }
  
  /* Not found */
  PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		    "No valid symbol interval", NULL);
}


/**
 * Return the symbol entry giving its name 
 * @param file target file
 * @param name dynamic symbol name
 * @return symbol pointer or NULL
 */
elfsh_Sym	*elfsh_get_dynsymbol_by_name(elfshobj_t *file, char *name)
{
  elfsh_Sym	*sym;
  int		idx;
  int		size = 0;
  char		*actual;
  elfshsect_t	*sect;

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);

  /* Check arguments */
  if (file == NULL || name == NULL)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		      "Invalid NULL parameter", NULL);

  sym = (elfsh_Sym *) elfsh_get_dynsymtab(file, &size);

  /* Check DYNSYM section data pointer */
  if (sym == NULL)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		 "Unable to get DYNSYM", NULL);

  sect = file->secthash[ELFSH_SECTION_DYNSYM];

  /* Check DYNSYM section pointer */
  if (sect == NULL)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		 "Unable to get DYNSYM section pointer", NULL);

  /*
  if (file->dynsymhash.ent)
    {
    //idx is the symbol number in the section
      idx = (int) hash_get(&file->dynsymhash, name);

#if __DEBUG_HASH_BY_NAME__
      printf("[DEBUG_HASH_BY_NAME] DYNSYM HASH Search by name for %s => %d\n",
	     name, idx);
#else
      //Check if idx is in the section
      if (idx <= 0 || idx >= sect->shdr->sh_size)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__,
		     "Symbol not found", NULL);
      
      PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (sym + idx));
#endif
    }
*/

  for (idx = 0; idx < size; idx++)
    {
      actual = elfsh_get_dynsymbol_name(file, sym + idx);
      if (actual != NULL && !strcmp(actual, name))
	{
#if __DEBUG_HASH_BY_NAME__
	  printf("[DEBUG_HASH_BY_NAME] DYNSYM ITERATE Search by name for %s => %d\n", 
		 name, idx);
#endif
	  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (sym + idx));
	}
    }

#if __DEBUG_HASH_BY_NAME__
  printf("[DEBUG_HASH_BY_NAME] DYNSYM ITERATE Search by name for %s => NOT FOUND\n", name);
#endif

  PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
	       "Symbol not found", NULL);
}



/**
 * Shift the dynamic symbol table, mostly useful on ET_DYN objects 
 * @param file
 * @param limit
 * @param inc
 * @return
 */
int		elfsh_shift_dynsym(elfshobj_t *file, eresi_Addr limit, int inc)
{
  elfshsect_t	*actual;
  int		err;

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);

  actual = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_ALTDYNSYM, 
				     NULL, NULL, NULL);
  if (!actual)
    {
      actual = elfsh_get_section_by_type(file, SHT_DYNSYM, 0, NULL, NULL, NULL);
      if (actual == NULL || actual->data == NULL)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__,
			  "Unable to find DYNSYM by type", -1);
    }

  err = elfsh_shift_syms(file, actual, limit, inc);
  if (err < 0)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__,
		      "Unable to shift DYNSYM", -1);

  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0);
}