/*
** libelfsh.h for libelfsh
** 
** Started on  Mon Jul 23 15:47:12 2001 mayhem
** Last update Mon Apr  1 12:32:21 2002 mayhem
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>


/* We are in debug mode, just comment it to avoid internal libelfsh messages to be printed in stdout */
//#define		__DEBUG__	1


/* Portability Stuffs */

#if defined(__OpenBSD__) || defined(__NetBSD__)
 #include <sys/exec_elf.h>
#elif defined(__linux__) || defined(__FreeBSD__) || defined(sun)
 #include <elf.h>
#endif 

#ifndef DT_BIND_NOW		/* undefined on BSD */
 #define DT_BIND_NOW	24
#endif

#ifndef STT_COMMON		/* undefined on debian */
 #define STT_COMMON	5
#endif

/* Legal values for sh_flags (section flags) undefined on (Free)BSD */

#ifndef SHF_WRITE
#define SHF_WRITE            (1 << 0)   /* Writable */
#endif 

#ifndef SHF_ALLOC
#define SHF_ALLOC            (1 << 1)   /* Occupies memory during execution */
#endif

#ifndef SHF_EXECINSTR
#define SHF_EXECINSTR        (1 << 2)   /* Executable */
#endif

#ifndef SHF_MERGE
#define SHF_MERGE            (1 << 4)   /* Might be merged */
#endif

#ifndef SHF_STRINGS
#define SHF_STRINGS          (1 << 5)   /* Contains nul-terminated strings */
#endif

#ifndef SHF_INFO_LINK
#define SHF_INFO_LINK        (1 << 6)   /* `sh_info' contains SHT index */
#endif

#ifndef SHF_LINK_ORDER
#define SHF_LINK_ORDER       (1 << 7)   /* Preserve order after combining */
#endif

#ifndef SHF_OS_NONCONFORMING
#define SHF_OS_NONCONFORMING (1 << 8)   /* Non-standard OS specific handling */
#endif

#ifndef SHF_MASKOS
#define SHF_MASKOS           0x0ff00000 /* OS-specific.  */
#endif

#ifndef SHF_MASKPROC
#define SHF_MASKPROC         0xf0000000 /* Processor-specific */
#endif


#if defined(sun)		/* SunOS has its own include */
 #include <strings.h>
 #include "libelfsh-sunos.h"
#endif

#if defined(sun)
 #define		ELFSH_ERR_ARRAY		strerror(errno)
#else
 #define		ELFSH_ERR_ARRAY		sys_errlist[sys_nerr]
#endif


/* Safe calloc() */
#define		XALLOC(a, b, c)				\
do							\
{							\
  if ((a = calloc(b, 1)) == NULL)			\
    ELFSH_SETERROR("libelfsh: Out of memory .", c);	\
}							\
while (0)


/* Safe realloc() */
#define		XREALLOC(a, b, c, d)			\
do							\
{							\
  if ((a = realloc(b, c)) == NULL)			\
    ELFSH_SETERROR("libelfsh: Out of memory .", d);	\
}							\
while (0)


/* Safe open() */
#define		XOPEN(a, b, c, d, e)	\
do					\
{					\
  if ((a = open(b, c, d)) < 0)		\
    return (e);				\
}					\
while (0)
     

/* Safe read() */
#define		XREAD(a, b, c, d)		\
do						\
{						\
  if (read(a, b, c) != c)			\
    ELFSH_SETERROR(ELFSH_ERR_ARRAY, d);		\
}						\
while (0)


/* Safe lseek() */
#define		XSEEK(a, b, c, d)		\
do						\
{						\
  if (lseek(a, b, c) == (int) b - 1)	        \
    ELFSH_SETERROR(ELFSH_ERR_ARRAY, d);		\
}						\
while (0)


/* Safe write */
#define		XWRITE(a, b, c, d)		\
do						\
{						\
  if (write(a, b, c) != c)			\
    return (d);					\
}						\
while (0)



/* Simple useful boolean macro */
#define		INTERVAL(a, b, c) (a <= b && b < c)



/*
** Some error stuffs : set the error offset of the file when calling SETERROR
** a: the file structure
** b: the string error
** c: the return value of the function
*/
#define ELFSH_SETERROR(b, c)		\
do					\
{					\
  elfsh_error_msg = (char *) b;		\
  return (c);				\
}					\
while (0)			


/* Just used to avoid code redundancy in elfsh_add_section() */
#define	ELFSH_SHIFT_SECTION(sct, tmp, mode)				\
do									\
{									\
  inserted = 1;								\
  if (mode >= ELFSH_SHIFTING_PARTIAL &&					\
      tmp->shdr->sh_link && (sct->index <= tmp->shdr->sh_link))		\
    tmp->shdr->sh_link++;						\
  if (mode == ELFSH_SHIFTING_COMPLETE)					\
    {									\
      if (tmp->shdr->sh_addr)					        \
        tmp->shdr->sh_addr += sct->shdr->sh_size;			\
      tmp->shdr->sh_offset += sct->shdr->sh_size;			\
      tmp->index++;							\
    }									\
}									\
while (0)
     


/* Some defined values */
#define		ELFSH_SECTION_NAME_MAPPED	".mapped"
#define		ELFSH_SECTION_NAME_UNMAPPED	".unmapped"

#define		ELFSH_SECTION_NAME_PLT		".plt"
#define		ELFSH_SECTION_NAME_DTORS	".dtors"
#define		ELFSH_SECTION_NAME_CTORS	".ctors"
#define		ELFSH_SECTION_NAME_GOT		".got"
#define		ELFSH_SECTION_NAME_INTERP	".interp"
#define		ELFSH_SECTION_NAME_STRTAB	".strtab"
#define		ELFSH_SECTION_NAME_SHSTRTAB	".shstrtab"
#define		ELFSH_SECTION_NAME_BSS		".bss"
#define		ELFSH_SECTION_NAME_TEXT		".text"
#define		ELFSH_SECTION_NAME_DATA		".data"
#define		ELFSH_SECTION_NAME_NOTES	".notes"
#define		ELFSH_SECTION_NAME_NOTES_ABI	".notes.ABI-tag"
#define		ELFSH_SECTION_NAME_DYNAMIC	".dynamic"

#define		ELFSH_PLT_ENTRY_SIZE	        16
#define		ELFSH_SYMTAB_ENTRY_SIZE		sizeof(Elf32_Sym)

#define		ELFSH_NULL_STRING		"(NULL)"
#define		ELFSH_SORT_BY_ADDR		'a'
#define		ELFSH_SORT_BY_SIZE		's'
#define		ELFSH_RULEZ_THE_WORLD		42

#define		ELFSH_SECTION_FIRST		0
#define		ELFSH_SECTION_LAST		0xFFFF
#define		ELFSH_FUNCTION_FIRST		0
#define		ELFSH_FUNCTION_LAST		0xFFFF

#define		ELFSH_SHIFTING_ABSENT		0
#define		ELFSH_SHIFTING_PARTIAL		1
#define		ELFSH_SHIFTING_COMPLETE		2




/* Extern variables */
extern char	*elfsh_error_msg;







/* --------------------- structures ------------------ */



/* Stab entry */
typedef struct		s_stab
{
  unsigned long		strindex;
  unsigned char		type;
  unsigned char		other;
  unsigned short	desc;
  unsigned int		value;
}			Elfsh32_Stab_ent;





/* Note section entry */
typedef struct		s_nentry
{
  int			namesz;
  int			descsz;
  int			type;
  char			*note;
  char			*desc;
  struct s_nentry	*next;
  struct s_nentry	*prev;
}			Elfsh32_Note_ent;




/* forward declaration */
struct			s_sect;	


/* Function type */
typedef struct		s_func
{
  Elf32_Sym		*sym;
  struct s_sect		*section;	/* section the function belongs to	*/
  int			offset;		/* Section offset for this function	*/
  int			len;		/* function real lenght			*/
  struct s_func		*next;
}			Elfsh32_Func;


/* Also use the same format for PLT entries */
typedef Elfsh32_Func	ELfsh32_Plt_ent;


/* forward declaration */
struct s_obj;



/* Section data type */
typedef struct		s_sect
{

  /* Filled at creation */
  Elf32_Phdr		*phdr;		/* the first parent segment					*/
  Elf32_Shdr		*shdr;		/* section header for this section				*/
  struct s_sect		*next;		/* next section in the list					*/
  struct s_sect		*prev;		/* prev section in the list					*/
  struct s_obj		*parent;	/* parent ELF object file					*/	
  int			index;		/* Section index in sht						*/
  char			flags;		/* Analysed/Raw, Orphelin/Child					*/
  char			*name;		/* Cached name							*/

  /* Filled at loading */
  void			*data;		/* section's data cache						*/
  int			nbr;		/* Number of units (section type dependant)			*/

  /* Filled at analysing */
  void			*altdata;	/* symtab stores a sorted table here, +x section stores the fht */
  int			altnbr;		/* Number of units for altdata					*/

}			Elfsh32_Sect;



/* ELFsh section states */
#define		ELFSH_SECTION_ANALYZED		(1 << 0)
#define		ELFSH_SECTION_INSERTED		(1 << 1)




/* Extended ELFsh section type list */
#define		ELFSH_SECTION_NULL		0
#define		ELFSH_SECTION_INTERP		1
#define		ELFSH_SECTION_NOTE		2
#define		ELFSH_SECTION_HASH		3
#define		ELFSH_SECTION_DYNSYM		4
#define		ELFSH_SECTION_DYNSTR		5
#define		ELFSH_SECTION_GNUVER		6
#define		ELFSH_SECTION_RELGOT		7
#define		ELFSH_SECTION_RELBSS		8
#define		ELFSH_SECTION_RELPLT		9
#define		ELFSH_SECTION_INIT		10
#define		ELFSH_SECTION_PLT		11
#define		ELFSH_SECTION_TEXT		12
#define		ELFSH_SECTION_FINI		13
#define		ELFSH_SECTION_RODATA		14
#define		ELFSH_SECTION_DATA		15
#define		ELFSH_SECTION_EHFRAME		16
#define		ELFSH_SECTION_CTORS		17
#define		ELFSH_SECTION_DTORS		18
#define		ELFSH_SECTION_GOT		19
#define		ELFSH_SECTION_DYNAMIC		20
#define		ELFSH_SECTION_SBSS		21
#define		ELFSH_SECTION_STAB		22
#define		ELFSH_SECTION_COMMENT		23
#define		ELFSH_SECTION_SHSTRTAB		24
#define		ELFSH_SECTION_SYMTAB		25
#define		ELFSH_SECTION_STRTAB		26
#define		ELFSH_SECTION_UNKNOWN		255






/* ELF object structure */
typedef struct	s_obj
{
  
  int		fd;		/* File descriptor for the original file */
  char		*name;		/* Object path */
  int		type;		/* ELFSH_OBJECT_CORE, ELFSH_OBJECT_SHARED, ELFSH_OBJECT_RELOC or ELFSH_OBJECT_EXEC */
  
  /* Elf headers */
  Elf32_Ehdr	*hdr;
  Elf32_Shdr	*sht;
  Elf32_Phdr	*pht;

  /* Section linked list */
  Elfsh32_Sect	*sections;

  /* Unlinked sections */
  Elfsh32_Sect	*sections_bean;

  /* ********************************************************************************** */
  /* The following variables point to their respective entry in the section linked list */
  /* ********************************************************************************** */

  /* Symbol table related fields */
  Elfsh32_Sect	*symtab;

  /* Dynamic symbol table related fields */
  Elfsh32_Sect	*dynsym;

  /* Stab section fields (debugging symbols) */
  Elfsh32_Sect	*stab;

  /* Symbol Hash (.hash) table fields */
  Elfsh32_Sect	*hash;

  /* Dynamic structure fields (PT_DYNAMIC) */
  Elfsh32_Sect	*dynamic;

  /* Constructors */
  Elfsh32_Sect	*ctors;

  /* Destructors */
  Elfsh32_Sect	*dtors;

  /* Global Offset Table fields */
  Elfsh32_Sect	*got;
  
  /* Procedure Linkage Table (.plt) object */
  Elfsh32_Sect	*plt;

  /* Interpretor section (PT_INTERP) */
  Elfsh32_Sect	*interp;

  /* Symbol string table (.strtab) */
  Elfsh32_Sect	*strtab;

  /* Stab string table (.stabstr) */
  Elfsh32_Sect	*stab_strtab;
  
  /* Dynamic symbol string table (.dynstr) */
  Elfsh32_Sect	*dyn_strtab;

  /* Section string table (.shstrtab) */
  Elfsh32_Sect	*sh_strtab;

  /* Various internal fields for error handling */
  char		buff[ELFSH_RULEZ_THE_WORLD];
  const char	*error;

  /* Has the object already been function scanned ? */
  char		scanned;		

  /* Do we include the sht in the output file ? Default is YES (1) */
  char		remove_sht_on_exit;

  /* The list is double linked */
  void		*next;
  void		*prev;

}		Elfsh32_Obj;






/* ----------------- prototypes -------------------------- */






/* libelfsh API, check api.txt for a complete description */


/* dynamic.c */
Elf32_Dyn	*elfsh_get_dynamic(Elfsh32_Obj *file, int *num);
Elf32_Dyn	*elfsh_get_dynamic_entry_by_type(Elfsh32_Obj *file, char type);
char		*elfsh_get_dynentry_info(Elfsh32_Obj *file, Elf32_Dyn *d);
u_int		elfsh_get_dynentry_type(Elf32_Dyn *d);

/* symbol.c */
Elf32_Sym	*elfsh_create_symbol(int value, int size, int type, int binding, int visibility);
Elf32_Sym	*elfsh_get_symbol_by_name(Elfsh32_Obj *file, char *name);
Elf32_Sym	*elfsh_copy_symtab(void *addr, int size);
Elf32_Sym	*elfsh_merge_symtabs(Elf32_Sym *one, Elf32_Sym *two, int size_one, int size_two);
Elf32_Sym	*elfsh_get_symbol_from_reloc(Elfsh32_Obj *file, Elf32_Rel *s);
char		*elfsh_reverse_symbol(Elfsh32_Obj *file, u_int sym_value, int *offset);
char		*elfsh_get_symbol_name(Elfsh32_Obj *file, Elf32_Sym *s);
void		*elfsh_get_symtab(Elfsh32_Obj *file, int *num);
void		*elfsh_get_symbol_offset(Elf32_Sym *s);
u_int		elfsh_get_symbol_bind(Elf32_Sym *s);
u_int		elfsh_get_symbol_type(Elf32_Sym *s);
int		elfsh_insert_symbol(Elfsh32_Sect *sect, Elf32_Sym *sym, char *name);
int		elfsh_get_symbol_foffset(Elfsh32_Obj *file, Elf32_Sym *sym);
int		elfsh_get_symbol_size(Elf32_Sym *s);
int		elfsh_sort_symtab(Elf32_Sym *symtab, int size, int type);

/* dynsym.c */
Elf32_Sym	*elfsh_get_dynsymbol_by_name(Elfsh32_Obj *file, char *name);
void		*elfsh_get_dynsymtab(Elfsh32_Obj *file, int *num);
char		*elfsh_reverse_dynsymbol(Elfsh32_Obj *file, u_int sym_value, int *offset);
char		*elfsh_get_dynsymbol_name(Elfsh32_Obj *file, Elf32_Sym *s);

/* elf.c */
void		*elfsh_get_hdr(Elfsh32_Obj *file);
Elfsh32_Obj	*elfsh_load_obj(char *name);
Elfsh32_Obj	*elfsh_map_obj(char *name);
u_int		elfsh_get_objtype(Elf32_Ehdr *e);
u_int		elfsh_get_arch(Elf32_Ehdr *e);
int		elfsh_load_hdr(Elfsh32_Obj *file);
void		elfsh_set_entry_point(Elfsh32_Obj *file, int addr);
void		elfsh_unload_obj(Elfsh32_Obj *file);

/* stab.c */
void		*elfsh_get_stab(Elfsh32_Obj *file, int *num);
void		*elfsh_get_stab_offset(Elfsh32_Stab_ent *s);	       
char		*elfsh_get_stab_name(Elfsh32_Obj *file, Elfsh32_Stab_ent *s);
u_int		elfsh_get_stab_type(Elfsh32_Stab_ent *s);

/* sht.c */
Elf32_Shdr      *elfsh_get_shtentry_from_sym(Elfsh32_Obj *file, Elf32_Sym *sym);
void		*elfsh_get_sht(Elfsh32_Obj *file, int *num);
char		*elfsh_get_section_name(Elfsh32_Obj *file, Elf32_Shdr *s);
int		elfsh_load_sht(Elfsh32_Obj *file);
int		elfsh_section_is_executable(Elf32_Shdr *s);
int		elfsh_section_is_writable(Elf32_Shdr *s);
int		elfsh_section_is_allocatable(Elf32_Shdr *s);
int		elfsh_section_is_mergeable(Elf32_Shdr *s);
int		elfsh_section_is_strtab(Elf32_Shdr *s);
int		elfsh_section_has_link(Elf32_Shdr *s);
int		elfsh_section_has_order(Elf32_Shdr *s);
int		elfsh_get_section_size(Elf32_Shdr *s);
int		elfsh_get_section_align(Elf32_Shdr *s);
int		elfsh_get_section_vaddr(Elf32_Shdr *s);
int		elfsh_get_section_foffset(Elf32_Shdr *s);
int		elfsh_insert_section_header(Elfsh32_Obj *file, Elf32_Shdr hdr, u_int range, char *name);
u_int		elfsh_get_section_type(Elf32_Shdr *s);
u_int		elfsh_get_section_info(Elf32_Shdr *s);
u_int		elfsh_get_section_entsize(Elf32_Shdr *s);
u_int		elfsh_get_section_link(Elf32_Shdr *s);
void		elfsh_remove_sht(Elfsh32_Obj *file);
void		elfsh_set_sht_offset(Elfsh32_Obj *file, int num);
void		elfsh_set_sht_nbr(Elfsh32_Obj *file, int num);
void		elfsh_set_section_info(Elf32_Shdr *s, Elf32_Word info);
void		elfsh_set_section_entsize(Elf32_Shdr *s, Elf32_Word entsize);
void		elfsh_set_section_link(Elf32_Shdr *s, Elf32_Word link);
void		elfsh_set_section_foffset(Elf32_Shdr *s, Elf32_Off offset);
void		elfsh_set_section_addr(Elf32_Shdr *s, Elf32_Addr addr);
Elf32_Shdr	elfsh_create_section_header(Elf32_Word name, Elf32_Word type, Elf32_Word flags,
					    Elf32_Addr addr, Elf32_Off offset, Elf32_Word size,
					    Elf32_Word link, Elf32_Word info, Elf32_Word align,
					    Elf32_Word entsize);


/* pht.c */
void		*elfsh_get_pht(Elfsh32_Obj *file, int *num);
Elf32_Phdr	*elfsh_get_segment_by_type(Elfsh32_Obj *file, int type, int range);
Elf32_Phdr	*elfsh_get_parent_segment(Elfsh32_Obj *file, Elfsh32_Sect *new);
int		elfsh_load_pht(Elfsh32_Obj *file);
int		elfsh_segment_is_writable(Elf32_Phdr *p);
int		elfsh_segment_is_readable(Elf32_Phdr *p);
int		elfsh_segment_is_executable(Elf32_Phdr *p);
int		elfsh_segment_is_parent(Elfsh32_Sect *new, Elf32_Phdr *p);
u_int		elfsh_get_segment_type(Elf32_Phdr *p);
void		elfsh_set_pht_offset(Elfsh32_Obj *file, int num);
void		elfsh_set_pht_nbr(Elfsh32_Obj *file, int num);



/* hash.c */
void		*elfsh_get_hashtable(Elfsh32_Obj *file);
int		elfsh_get_symbol_hash(char *sym_name);
int		elfsh_get_dynsymbol_by_hash(Elfsh32_Obj *file, char *sym_name);

/* got.c */
void		*elfsh_get_got(Elfsh32_Obj *file, int *num);
int		elfsh_set_got_entry(Elfsh32_Obj *file, int index, int new_addr);

/* dtors.c */
void		*elfsh_get_dtors(Elfsh32_Obj *file, int *num);
int		elfsh_set_dtors_entry_by_index(Elfsh32_Obj *file, int index, int new_addr);
int		elfsh_set_dtors_entry_by_name(Elfsh32_Obj *file, char *name, int new_addr);

/* ctors.c */
void		*elfsh_get_ctors(Elfsh32_Obj *file, int *num);
int		elfsh_set_ctors_entry_by_name(Elfsh32_Obj *file, char *name, int new_addr);
int		elfsh_set_ctors_entry_by_index(Elfsh32_Obj *file, int index, int new_addr);

/* section.c */
Elfsh32_Sect	*elfsh_get_section_by_type(Elfsh32_Obj *, u_int, int *, int *, int *, int);
Elfsh32_Sect	*elfsh_get_section_by_index(Elfsh32_Obj *, int, int *, int *);
Elfsh32_Sect	*elfsh_get_section_by_name(Elfsh32_Obj *, char *, int *, int *, int *);
Elfsh32_Sect	*elfsh_get_parent_section(Elfsh32_Obj *file, u_int value, int *offset);
Elfsh32_Sect	*elfsh_get_parent_section_by_foffset(Elfsh32_Obj *file, u_int value, int *offset);
Elfsh32_Sect	*elfsh_create_section(char *name);
void		*elfsh_load_section(Elfsh32_Obj *file, Elf32_Shdr *shdr);
void		*elfsh_get_anonymous_section(Elfsh32_Obj *file, Elfsh32_Sect *sect);
int		elfsh_add_section(Elfsh32_Obj *file, Elfsh32_Sect *sect, u_int index, void *data, int shift);
int		elfsh_append_data_to_section(Elfsh32_Sect *sect, void *input, int len);


/* rel.c */
Elfsh32_Sect	*elfsh_get_reloc(Elfsh32_Obj *file, u_int range, char *name, u_int *num);
void		*elfsh_get_reloffset(Elfsh32_Obj *file, Elf32_Rel *r);
void		elfsh_free_reloc_list(Elfsh32_Obj *file);
u_int		elfsh_get_reloc_type(Elf32_Rel *r);


/* interp.c */
char		*elfsh_get_interp(Elfsh32_Obj *file);

/* notes */
Elfsh32_Sect	*elfsh_get_notes(Elfsh32_Obj *file, u_int range, char *name);
void		elfsh_free_notes_list(Elfsh32_Obj *file);

/* functions.c */
Elfsh32_Func	*elfsh_get_function_by_addr(Elfsh32_Obj *file, int addr);
Elfsh32_Func    *elfsh_get_function_by_name(Elfsh32_Obj *file, char *name);
int		elfsh_get_function_len(Elfsh32_Func *func);
int		elfsh_get_function_addr(Elfsh32_Func *func);
int		elfsh_insert_function(Elfsh32_Sect *sct, Elfsh32_Func *fct, int range);
int		elfsh_scan_functions(Elfsh32_Obj *file);
int		elfsh_sort_functions(Elfsh32_Obj *file);

/* plt.c */
Elfsh32_Sect	*elfsh_get_plt(Elfsh32_Obj *file, int *num);
int		elfsh_is_pltentry(Elfsh32_Obj *file, Elf32_Sym *sym);
int		elfsh_is_plt(Elfsh32_Obj *file, Elf32_Shdr *s);

/* raw.c */
int		elfsh_raw_write(Elfsh32_Obj *file, u_int dst, void *src, int len);
int		elfsh_raw_read(Elfsh32_Obj *file, u_int dst, void *src, int len);
int		elfsh_get_foffset_from_vaddr(Elfsh32_Obj *file, u_int vaddr);

/* map.c */
int		elfsh_save_obj(Elfsh32_Obj *file, char *name);

/* strtab.c */
int		elfsh_insert_in_strtab(Elfsh32_Obj *file, char *name);
int		elfsh_insert_in_shstrtab(Elfsh32_Obj *file, char *name);

/* error.c */
void		elfsh_error();

/* fixup.c */
int		elfsh_fixup_bss(Elfsh32_Obj *file);

/* sht_rebuild.c */
int		elfsh_rebuild_sht(Elfsh32_Obj *file);












