/*
** pht.c for libelfsh
** 
** Started on  Mon Feb 26 04:07:33 2001 mayhem
** Last update Sat Mar 30 18:33:45 2002 mayhem
*/
#include "libelfsh.h"







/* Return the segment type giving its p_type member */
u_int	elfsh_get_segment_type(Elf32_Phdr *p)
{
  return (p->p_type);
}

/* Set the type for this segment */
void	elfsh_set_segment_type(Elf32_Phdr *p, int type)
{
  p->p_type = type;
}

/* 3 tiny functions to retreive the rights for a segment */
int	elfsh_segment_is_readable(Elf32_Phdr *p)
{
  return ((p->p_flags & PF_R));
}

int	elfsh_segment_is_writable(Elf32_Phdr *p)
{
  return ((p->p_flags & PF_W));
}

int	elfsh_segment_is_executable(Elf32_Phdr *p)
{
  return ((p->p_flags & PF_X));
}


/* Tiny write access functions for program headers */
void	elfsh_set_segment_flags(Elf32_Phdr *p, int mask)
{
  p->p_flags = mask;
}

void	elfsh_set_segment_align(Elf32_Phdr *p, int align)
{
  p->p_align = align;
}

void	elfsh_set_segment_memsz(Elf32_Phdr *p, int memsz)
{
  p->p_memsz = memsz;
}

void	elfsh_set_segment_filesz(Elf32_Phdr *p, int filesz)
{
  p->p_filesz = filesz;
}

void	elfsh_set_segment_paddr(Elf32_Phdr *p, int paddr)
{
  p->p_paddr = paddr;
}

void	elfsh_set_segment_vaddr(Elf32_Phdr *p, int vaddr)
{
  p->p_vaddr = vaddr;
}




/* Return an array of program (segment) header */
int		elfsh_load_pht(Elfsh32_Obj *file)
{
  int		size;

  if (!file || (!file->hdr && elfsh_load_hdr(file) == -1))
    return (-1);
  else if (file->pht)
    return (0);

  if (!file->hdr->e_phoff)
    ELFSH_SETERROR("libelfsh: No PHT .", -1);

  size = file->hdr->e_phentsize * file->hdr->e_phnum;
  XSEEK(file->fd, file->hdr->e_phoff, SEEK_SET, -1);
  XALLOC(file->pht, size, -1);
  XREAD(file->fd, file->pht, size, -1);
  return (0);

}




/* Retreive the 'range'th segment header of type 'type' */
Elf32_Phdr	*elfsh_get_segment_by_type(Elfsh32_Obj *file, int type, int range)
{
  Elf32_Phdr	*pht;
  int		index;
  int		max;
  int		cnt;

  pht = elfsh_get_pht(file, &max);
  if (!pht)
    return (NULL);
  
  for (cnt = index = 0; index < max; index++)
    if (elfsh_get_segment_type(pht + index) == type)
      {
	if (cnt == range)
	  return (&pht[index]);
	cnt++;
      }

  return (NULL);
}





/* Get the parent segment for this section */
Elf32_Phdr	*elfsh_get_parent_segment(Elfsh32_Obj *file, Elfsh32_Sect *new)
{
  Elf32_Phdr	*actual;
  int		index;

  if (!new->parent->pht && elfsh_load_pht(new->parent) < 0)
    return (NULL);

  for (index = 0, actual = new->parent->pht; index < new->parent->hdr->e_phnum; index++)
    if (INTERVAL(actual[index].p_vaddr, new->shdr->sh_addr, actual[index].p_vaddr + actual[index].p_memsz))
      return (actual + index);
  return (NULL);
}





/* Tell if the section belongs to the segment or not */
int		elfsh_segment_is_parent(Elfsh32_Sect *new, Elf32_Phdr *p)
{
  if (INTERVAL(p->p_offset, new->shdr->sh_offset, p->p_offset + p->p_filesz))
    return (1);
  return (0);
}






/* Return a ptr on the program header table */
void	*elfsh_get_pht(Elfsh32_Obj *file, int *num)
{
  if (file->pht == 0 && elfsh_load_pht(file) == -1)
    return (NULL);
  if (num)
    *num = file->hdr->e_phnum;
  return (file->pht);
}















