
#include <cstdio>
#include <cstring>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <sys/types.h>
#include <unistd.h>
#include <dlfcn.h>
#include <cmath>

#include "ELFIO.h"

using namespace std;

int main(int argc, char* argv[])
{
  if(argc < 2)
    {
      cerr << "usage: " << argv[0] << " exe_file" << endl;
      return -1;
    }

  ELFIO_Err rc;
  const ELFIO* inst = ELFIO::GetInstance();
  IELFI* e;

  if(inst->CreateELFI(&e)!=ERR_ELFIO_NO_ERROR)
    {
      cerr << "failed to init elf reader: " << endl;
      return -1;
    }

  if((rc=e->Load(argv[1]))!=ERR_ELFIO_NO_ERROR)
    {
      cerr << "failed: " << inst->GetErrorText(rc) << endl;
      return -1;
    }

  Elf32_Half tot = e->GetSegmentsNum();
  for(Elf32_Half i=0;i<tot;++i)
    {
      const IELFISegment* seg = e->GetSegment(i);
      if(seg->GetType()==PT_LOAD && seg->GetFlags()&PF_X)
	{
	  cout << "virt=" << (void*)seg->GetVirtualAddress() << " "
	       << "phys=" << (void*)seg->GetPhysicalAddress()
	       << endl;
	}
    }

  tot = e->GetSectionsNum();
  for(Elf32_Half i=0;i<tot;++i)
    {
      const IELFISection* seg = e->GetSection(i);
      if(seg->GetType()==SHT_DYNSYM)
	{
	  cout << "name=(" << seg->GetName() << ") "
	       << "address=" << (void*)seg->GetAddress() << " "
	       << endl;

	  IELFISymbolTable* p;
	  rc=e->CreateSectionReader(IELFI::ELFI_SYMBOL,seg,(void**)&p);
	  if(rc!=ERR_ELFIO_NO_ERROR)
	    {
	      cerr << "could not get section reader" << endl;
	      continue;
	    }

	  Elf32_Word n = p->GetSymbolNum();
	  Elf32_Word size;
	  Elf32_Half section;
	  Elf32_Addr value;
	  unsigned char bind;
	  unsigned char type;
	  string sym_name;

	  for(int i=0;i<n;++i)
	    {
	      rc=p->GetSymbol(i,sym_name,value,size,bind,type,section);

	      if(rc!=ERR_ELFIO_NO_ERROR)
		{
		  cerr << "could not get symbol " << i << endl;
		  continue;
		}

	      switch(bind)
		{
		case STB_LOCAL:
		case STB_GLOBAL:
		case STB_WEAK:
		  if(sym_name.size() && (type==STT_FUNC || type==STT_OBJECT))
		    cout << sym_name << " "
			 << (void*)value << " "
			 << size << " "
			 << section << " "
			 << (int)type << " "
			 << (int)bind
			 << endl;
		}
	    }
	  p->Release();
	}
      seg->Release();
    }  

  e->Release();
  return 0;
}
