/*
** hexa.c for elfsh
** 
** Started on  Thu Feb 28 16:33:57 2002 mayhem
** Last update Sun Mar 10 08:27:30 2002 mayhem
*/
#include "elfsh.h"





/* Print data in hexadecimal and ascii */
int             print_hexa(Elfsh32_Obj *file, char *name, u_int vaddr, u_int foffset, int len, u_int type)
{
  char		*base = "0123456789ABCDEF";
  char		*buff;
  int		index;
  int		value;
  char		off[256];
  int		offset;


  /* The object has an invalid vaddr */
  if (!foffset)
    {
      printf(" => Object has an invalid file offset !");
      return (0);
    }
  
  /* Get data from the filemap */
  if (!len)
    {
      printf(" => Object has a NULL size field !");
      return (0);
    }

  /* Read data from input file */
  XALLOC(buff, len, 0);
  len = elfsh_raw_read(file, foffset, buff, len);
  if (!len)
    {
      printf(" => Cant read requested amount of data (corrupted symbol size field ?)");
      free(buff);
      return (0);
    }

  /* If the symbol is just a tiny variable , we print it on 1 line */
  else if (type != STT_FUNC && type != STT_SECTION && len <= 4)
    {
      value = *(int *) buff;
      printf(" => Hexadecimal(%X) Decimal(%u) Octal(%o) ", value, value, value);
      free(buff);
      return (len);
    }

  
  putchar('\n');


  /* Print in hexadecimal doing reverse symbol matching */
  for (index = 0; index < len; index += 8)
    {

      /* For non-mapped sections */
      if (!vaddr)
	elfsh_get_parent_section_by_foffset(file, foffset + index, &offset);
      else
	{
	  name = elfsh_reverse_symbol(file, vaddr + index, &offset);
	  if (!name)
	    name = ELFSH_NULL_STRING;
	}
      
      /* Do the nice output ;) */
      if (offset)
	snprintf(off, sizeof(off), " + %u", offset);
      else
	snprintf(off, sizeof(off), "\t");
      
      /* Print it */
      printf("\n %40s%s \t%s %10p : \t\t %c%c %c%c %c%c %c%c  %c%c %c%c %c%c %c%c \t %c%c%c%c%c%c%c%c",
	     name, off, (offset > 0 && offset < 100 ? "\t" : ""), (void *) vaddr + index,
	     (index + 0 >= len ? ' ' : base[(buff[index] >> 4) & 0x0F]),
	     (index + 0 >= len ? ' ' : base[buff[index] & 0x0F]),
	     (index + 1 >= len ? ' ' : base[(buff[index + 1] >> 4) & 0x0F]),
	     (index + 1 >= len ? ' ' : base[buff[index + 1] & 0x0F]),
	     (index + 2 >= len ? ' ' : base[(buff[index + 2] >> 4) & 0x0F]),
	     (index + 2 >= len ? ' ' : base[buff[index + 2] & 0x0F]),
	     (index + 3 >= len ? ' ' : base[(buff[index + 3] >> 4) & 0x0F]),
	     (index + 3 >= len ? ' ' : base[buff[index + 3] & 0x0F]),
	     (index + 4 >= len ? ' ' : base[(buff[index + 4] >> 4) & 0x0F]),
	     (index + 4 >= len ? ' ' : base[buff[index + 4] & 0x0F]),
	     (index + 5 >= len ? ' ' : base[(buff[index + 5] >> 4) & 0x0F]),
	     (index + 5 >= len ? ' ' : base[buff[index + 5] & 0x0F]),
	     (index + 6 >= len ? ' ' : base[(buff[index + 6] >> 4) & 0x0F]),
	     (index + 6 >= len ? ' ' : base[buff[index + 6] & 0x0F]),
	     (index + 7 >= len ? ' ' : base[(buff[index + 7] >> 4) & 0x0F]),
	     (index + 7 >= len ? ' ' : base[buff[index + 7] & 0x0F]),
	     (index + 0 >= len ? ' ' : PRINTABLE(buff[index + 0]) ? buff[index + 0] : '.'),
	     (index + 1 >= len ? ' ' : PRINTABLE(buff[index + 1]) ? buff[index + 1] : '.'),
	     (index + 2 >= len ? ' ' : PRINTABLE(buff[index + 2]) ? buff[index + 2] : '.'),
	     (index + 3 >= len ? ' ' : PRINTABLE(buff[index + 3]) ? buff[index + 3] : '.'),
	     (index + 4 >= len ? ' ' : PRINTABLE(buff[index + 4]) ? buff[index + 4] : '.'),
	     (index + 5 >= len ? ' ' : PRINTABLE(buff[index + 5]) ? buff[index + 5] : '.'),
	     (index + 6 >= len ? ' ' : PRINTABLE(buff[index + 6]) ? buff[index + 6] : '.'),
	     (index + 7 >= len ? ' ' : PRINTABLE(buff[index + 7]) ? buff[index + 7] : '.'));

    }


  puts("\n");
  free(buff);
  return (0);

}





/* Display file objects in hexadecimal */
int             display_hexa(Elfsh32_Obj *file, argv_t *av)
{
  list_t	*actual;
  char		*name;
  int		index;
  int		type;
  int		value;
  int		foffset;
  int		symtab_num;
  int		sht_num;
  char		buff[BUFSIZ];
  Elf32_Shdr	*sht;
  Elf32_Sym	*symtab;


  /* Use the section header table if we dont have a symtab */
  symtab = (Elf32_Sym *) elfsh_get_symtab(file, &symtab_num);
  sht = (Elf32_Shdr *) elfsh_get_sht(file, &sht_num);
  elfsh_scan_functions(file);
  if (!symtab && !sht)
    RET(-1);
  puts("\n[HEXADECIMAL VIEW]\n");


  /* For each element of the requested pattern list */
  /* Do a first pass using SHT since its the only way to have an output for section with NULL vaddr */
  for (actual = av->hexa; sht && actual; actual = actual->next)
    for (index = 0; index < sht_num; index++)
      {
	
	/* Get info */
	value   = elfsh_get_section_vaddr(sht + index);
	foffset = elfsh_get_section_foffset(sht + index);
	name = elfsh_get_section_name(file, sht + index);
	if (name == NULL)
	  name = ELFSH_NULL_STRING;
	
	/* Print the header for this symbol */
	snprintf(buff, sizeof(buff), "\n{-- 0x%08X \t %-30s (Section size : %u bytes) \t --}",  
		 value, name, sht[index].sh_size);
	
	/* Does it match the regex ? */
	if (!regexec(&actual->name, buff, 0, 0, 0))
	  {
	    printf("%s", buff);
	    fflush(stdout);
	    print_hexa(file, name, value, foffset, sht[index].sh_size, STT_SECTION);
	  }
      }



  /* Do a second pass , this time using the symbol table, ignoring Section symbols */
  for (actual = av->hexa; symtab && actual; actual = actual->next)
    for (index = 0; index < symtab_num; index++)
      if (elfsh_get_symbol_type(symtab + index) != STT_SECTION)
	{
	  
	  /* Get info */
	  value = symtab[index].st_value;
	  foffset = elfsh_get_foffset_from_vaddr(file, value);
	  name = elfsh_get_symbol_name(file, symtab + index);
	  type = elfsh_get_symbol_type(symtab + index);
	  if (name == NULL)
	    name = ELFSH_NULL_STRING;
	  
	  /* Print the header for this symbol */
	  snprintf(buff, sizeof(buff), "\n{-- 0x%08X \t %-30s (%s size : %u bytes) \t --}", value, name, 
		   (type == STT_FUNC   ? "Function" : type == STT_COMMON ? "Common"   : 
		    type == STT_OBJECT ? "Variable" : type == STT_FILE   ? "Filename" : "Unknown"),
		   symtab[index].st_size);
	  
	  /* Does it match the regex ? */
	  if (!regexec(&actual->name, buff, 0, 0, 0) && (type == STT_FUNC || type == STT_OBJECT || type == STT_COMMON))
	    {
	      printf("%s", buff);
	      fflush(stdout);
	      print_hexa(file, name, value, foffset, symtab[index].st_size, type);
	    }
	  
	}

  return (-1);

}




















