/*
** map.c for libelfsh
** 
** Started on  Sat Mar  2 20:47:36 2002 mayhem
** Last update Thu Jun  6 05:24:28 2002 mayhem
*/
#include "libelfsh.h"





/* Map in memory all ressources for this file */
Elfsh32_Obj	*elfsh_map_obj(char *name)
{
  Elfsh32_Obj	*file;
  Elfsh32_Sect	*actual;
  int		index;

  /* Load headers */
  if ((file = elfsh_load_obj(name)) == NULL)
    return (NULL);
  if (elfsh_get_sht(file, NULL) == NULL)
    return (NULL);
  if (!elfsh_get_pht(file, NULL))
    return (NULL);

#ifdef __DEBUG__
  /* Load all known-typed sections */
  puts("[LIBELFSH] Loading all known sections ... ");
#endif


  /* We cannot use elfsh_get_anonymous_section() since the ptrs in the Elfsh32_Obj would not be filled */
  elfsh_get_symtab(file, NULL);
  elfsh_get_dynsymtab(file, NULL);
  elfsh_scan_functions(file);
  elfsh_get_stab(file, NULL);
  elfsh_get_dynamic(file, NULL);
  elfsh_get_ctors(file, NULL);
  elfsh_get_dtors(file, NULL);    
  elfsh_get_got(file, NULL);
  elfsh_get_interp(file);
  elfsh_get_hashtable(file);
  

  /* Fill Notes sections and relocations sections */
  for (index = 0; elfsh_get_reloc(file, index, NULL, NULL); index++);
  for (index = 0; elfsh_get_notes(file, index, NULL); index++);
  
  /* Loop on the section header table and load all unknown-typed sections */
  for (actual = file->sections; actual; actual = actual->next)
    if (!actual->data && actual->shdr->sh_size && 
	!(actual->next && actual->next->shdr->sh_offset == actual->shdr->sh_offset))
      {

#ifdef __DEBUG__
	printf("[LIBELFSH] Loading unknown sections %s \n", elfsh_get_section_name(file, actual->shdr));
#endif

	elfsh_get_anonymous_section(file, actual);
      }

  return (file);

}






/* Unmap and free all ressources for this file */
int		elfsh_save_obj(Elfsh32_Obj *file, char *name)
{
  int		fd;
  char		written_sht;
  Elfsh32_Sect	*actual;

  /* Create the file, write the elf header and the pht, then parse sections */
  if (!file || !file->pht || !file->sht || !file->sections)
    ELFSH_SETERROR("elfsh_save_obj: Invalid Elfsh32_Obj parameter . \n", -1);
  XOPEN(fd, name, O_CREAT | O_RDWR, 0700, -1);

  /* Strip the sht is requested */
  if (file->remove_sht_on_exit)
    {
      file->hdr->e_shoff = 0;
      file->hdr->e_shstrndx = 0;
      file->hdr->e_shnum = 0;
    }

  /* Write the elf header and the program header table */
  XWRITE(fd, file->hdr, file->hdr->e_ehsize, -1);
  XWRITE(fd, file->pht, file->hdr->e_phentsize * file->hdr->e_phnum, -1);
  

  /* Write each sections in the detination file at their respective offset */
  for (written_sht = 0, actual = file->sections; actual; actual = actual->next)
    {

      /* If the sht has not been written yet and the current section file offset is bigger */
      if (!written_sht && !file->remove_sht_on_exit && actual->shdr->sh_offset > file->hdr->e_shoff)
	{

#ifdef __DEBUG__
	  printf("[LIBELFSH] Writing SHT (file offset %u, size %u) \n", 
		 file->hdr->e_shoff, file->hdr->e_shentsize * file->hdr->e_shnum);
#endif

	  XSEEK(fd, file->hdr->e_shoff, SEEK_SET, -1);
	  XWRITE(fd, file->sht, file->hdr->e_shnum * file->hdr->e_shentsize, -1);
	  written_sht = 1;
	}
      
      /* We do the check to avoid null sized section like .sbss to fool us */
      if (actual->data && actual->shdr->sh_size && 
	  !(actual->next && actual->next->shdr->sh_offset == actual->shdr->sh_offset))
	{
	  
#ifdef __DEBUG__
	  printf("[LIBELFSH] Writing section %30s \t (hdr: %-20s index %02u, file offset %08u, size %08u) \n", 
		 actual->name, elfsh_get_section_name(file, actual->shdr), 
		 actual->index, elfsh_get_section_foffset(actual->shdr),
		 elfsh_get_section_size(actual->shdr));
#endif	  

	  /* write the section */
	  XSEEK(fd, elfsh_get_section_foffset(actual->shdr), SEEK_SET, -1);
	  XWRITE(fd, actual->data, actual->shdr->sh_size, -1);
	  
	}

#ifdef __DEBUG__      
      else
	printf("[LIBELFSH] Passing section %30s \t (hdr: %-20s index %02u, file offset %08u, size %08u) \n", 
	       actual->name, elfsh_get_section_name(file, actual->shdr), 
	       actual->index, elfsh_get_section_foffset(actual->shdr),
	       elfsh_get_section_size(actual->shdr));
#endif

    }



  /* If the sht has not been written yet and the current section file offset is bigger */
  if (!written_sht && !file->remove_sht_on_exit)
    {

#ifdef __DEBUG__
      printf("[LIBELFSH] Writing SHT at the end (file offset %u, size %u) \n", 
	     file->hdr->e_shoff, file->hdr->e_shentsize * file->hdr->e_shnum);
#endif

      XSEEK(fd, file->hdr->e_shoff, SEEK_SET, -1);
      XWRITE(fd, file->sht, file->hdr->e_shnum * file->hdr->e_shentsize, -1);
    }



  close(fd);
  return (0);

}







