#!/usr/bin/perl -w
################################################################################
#
# Copyright (c) 2005-2024 Marcus Holland-Moritz. All rights reserved.
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself.
#
################################################################################

use Convert::Binary::C;
use Data::Dumper;
use Getopt::Long;
use strict;

#-------------------------------------------------
# Constants for accessing ELF identification data
#-------------------------------------------------
use constant EI_CLASS => 4;
use constant EI_DATA  => 5;

my %opt;
Getopt::Long::Configure('bundling');
unless (GetOptions(\%opt, qw( list|l info|i debug section|s=s symbols ))) {
  eval q{
    require Pod::Usage;
    Pod::Usage::pod2usage(2);
  };
  print "Cannot show help, please consider installing Pod::Usage.\n";
  exit;
}

unless (@ARGV) {
  print "No input file (try '$0 -h' for usage).\n";
  exit;
}

#---------------------------------------------------
# Compiler Configuration (generated using ccconfig)
#---------------------------------------------------
my %config = (
  Alignment         => 4,
  CharSize          => 1,
  CompoundAlignment => 1,
  IntSize           => 4,
  LongLongSize      => 8,
  LongSize          => 4,
  ShortSize         => 2,
  UnsignedChars     => 0
);

#-----------
# ELF Types
#-----------
my @elftype = qw( ET_NONE ET_REL ET_EXEC ET_DYN ET_CORE );

#-------------------
# ELF Section Types
#-------------------
my @sectype = qw(
  SHT_NULL SHT_PROGBITS SHT_SYMTAB SHT_STRTAB SHT_RELA SHT_HASH
  SHT_DYNAMIC SHT_NOTE SHT_NOBITS SHT_REL SHT_SHLIB SHT_DYNSYM
);

#-------------------
# ELF Segment Types
#-------------------
my @segtype = qw(
  PT_NULL PT_LOAD PT_DYNAMIC PT_INTERP PT_NOTE PT_SHLIB PT_PHDR
);

#-------------------
# ELF Machine Types
#-------------------
my %machine = (
   0 => 'EM_NONE (No machine)',
   1 => 'EM_M32 (AT&T WE 32100)',
   2 => 'EM_SPARC (SUN SPARC)',
   3 => 'EM_386 (Intel 80386)',
   4 => 'EM_68K (Motorola m68k family)',
   5 => 'EM_88K (Motorola m88k family)',
   7 => 'EM_860 (Intel 80860)',
   8 => 'EM_MIPS (MIPS R3000 big-endian)',
   9 => 'EM_S370 (IBM System/370)',
  10 => 'EM_MIPS_RS3_LE (MIPS R3000 little-endian)',
  15 => 'EM_PARISC (HPPA)',
  17 => 'EM_VPP500 (Fujitsu VPP500)',
  18 => 'EM_SPARC32PLUS (Sun\'s "v8plus")',
  19 => 'EM_960 (Intel 80960)',
  20 => 'EM_PPC (PowerPC)',
  21 => 'EM_PPC64 (PowerPC 64-bit)',
  22 => 'EM_S390 (IBM S390)',
  36 => 'EM_V800 (NEC V800 series)',
  37 => 'EM_FR20 (Fujitsu FR20)',
  38 => 'EM_RH32 (TRW RH-32)',
  39 => 'EM_RCE (Motorola RCE)',
  40 => 'EM_ARM (ARM)',
  41 => 'EM_FAKE_ALPHA (Digital Alpha)',
  42 => 'EM_SH (Hitachi SH)',
  43 => 'EM_SPARCV9 (SPARC v9 64-bit)',
  44 => 'EM_TRICORE (Siemens Tricore)',
  45 => 'EM_ARC (Argonaut RISC Core)',
  46 => 'EM_H8_300 (Hitachi H8/300)',
  47 => 'EM_H8_300H (Hitachi H8/300H)',
  48 => 'EM_H8S (Hitachi H8S)',
  49 => 'EM_H8_500 (Hitachi H8/500)',
  50 => 'EM_IA_64 (Intel Merced)',
  51 => 'EM_MIPS_X (Stanford MIPS-X)',
  52 => 'EM_COLDFIRE (Motorola Coldfire)',
  53 => 'EM_68HC12 (Motorola M68HC12)',
  54 => 'EM_MMA (Fujitsu MMA Multimedia Accelerator)',
  55 => 'EM_PCP (Siemens PCP)',
  56 => 'EM_NCPU (Sony nCPU embeeded RISC)',
  57 => 'EM_NDR1 (Denso NDR1 microprocessor)',
  58 => 'EM_STARCORE (Motorola Start*Core processor)',
  59 => 'EM_ME16 (Toyota ME16 processor)',
  60 => 'EM_ST100 (STMicroelectronic ST100 processor)',
  61 => 'EM_TINYJ (Advanced Logic Corp. Tinyj emb.fam)',
  62 => 'EM_X86_64 (AMD x86-64 architecture)',
  63 => 'EM_PDSP (Sony DSP Processor)',
  66 => 'EM_FX66 (Siemens FX66 microcontroller)',
  67 => 'EM_ST9PLUS (STMicroelectronics ST9+ 8/16 mc)',
  68 => 'EM_ST7 (STmicroelectronics ST7 8 bit mc)',
  69 => 'EM_68HC16 (Motorola MC68HC16 microcontroller)',
  70 => 'EM_68HC11 (Motorola MC68HC11 microcontroller)',
  71 => 'EM_68HC08 (Motorola MC68HC08 microcontroller)',
  72 => 'EM_68HC05 (Motorola MC68HC05 microcontroller)',
  73 => 'EM_SVX (Silicon Graphics SVx)',
  74 => 'EM_ST19 (STMicroelectronics ST19 8 bit mc)',
  75 => 'EM_VAX (Digital VAX)',
  76 => 'EM_CRIS (Axis Communications 32-bit embedded processor)',
  77 => 'EM_JAVELIN (Infineon Technologies 32-bit embedded processor)',
  78 => 'EM_FIREPATH (Element 14 64-bit DSP Processor)',
  79 => 'EM_ZSP (LSI Logic 16-bit DSP Processor)',
  80 => 'EM_MMIX (Donald Knuth\'s educational 64-bit processor)',
  81 => 'EM_HUANY (Harvard University machine-independent object files)',
  82 => 'EM_PRISM (SiTera Prism)',
  83 => 'EM_AVR (Atmel AVR 8-bit microcontroller)',
  84 => 'EM_FR30 (Fujitsu FR30)',
  85 => 'EM_D10V (Mitsubishi D10V)',
  86 => 'EM_D30V (Mitsubishi D30V)',
  87 => 'EM_V850 (NEC v850)',
  88 => 'EM_M32R (Mitsubishi M32R)',
  89 => 'EM_MN10300 (Matsushita MN10300)',
  90 => 'EM_MN10200 (Matsushita MN10200)',
  91 => 'EM_PJ (picoJava)',
  92 => 'EM_OPENRISC (OpenRISC 32-bit embedded processor)',
  93 => 'EM_ARC_A5 (ARC Cores Tangent-A5)',
  94 => 'EM_XTENSA (Tensilica Xtensa Architecture)',
);

#-----------------------------
# ELF Symbol Binding and Type
#-----------------------------
my %symbind = (
   0 => 'STB_LOCAL',
   1 => 'STB_GLOBAL',
   2 => 'STB_WEAK',
   3 => 'STB_NUM',
  10 => 'STB_LOOS',
  12 => 'STB_HIOS',
  13 => 'STB_LOPROC',
  15 => 'STB_HIPROC',
);

my %symtype = (
   0 => 'STT_NOTYPE',
   1 => 'STT_OBJECT',
   2 => 'STT_FUNC',
   3 => 'STT_SECTION',
   4 => 'STT_FILE',
   5 => 'STT_COMMON',
   6 => 'STT_TLS',
   7 => 'STT_NUM',
  10 => 'STT_LOOS',
  12 => 'STT_HIOS',
  13 => 'STT_LOPROC',
  15 => 'STT_HIPROC',
);

#--------------------------------------------------------
# Create a C::B::C object to convert ELF data structures
#--------------------------------------------------------
my $ep = Convert::Binary::C->new(%config)->parse(elf_header());

#-------------------------------------------
# Attach hooks to certain interesting types
#-------------------------------------------
my %hook = (
  'Ehdr.e_machine' => \%machine,
  'Ehdr.e_type'    => \@elftype,
  'Shdr.sh_type'   => \@sectype,
  'Phdr.p_type'    => \@segtype,
);

for my $c (qw( Elf32 Elf64 )) {
  while (my($k,$v) = each %hook) {
    $ep->tag("$c\_$k", Hooks => { unpack => sub {
      my $x = shift; (ref $v eq 'HASH' ? $v->{$x} : $v->[$x]) || "Unknown ($x)"
    }});
  }

  $ep->tag("$c\_Sym.st_info", Hooks => { unpack => sub {
    my $x = shift;
    my $b = $x >> 4;
    my $t = $x & 0xf;
    {
      sti_bind => $symbind{$b} || "Unknown ($b)",
      sti_type => $symtype{$t} || "Unknown ($t)",
    }
  }});
}

#---------------------------------------
# Read the whole ELF file (inefficient)
#---------------------------------------
my $elf = do { local($/, *FH);
               open FH, $ARGV[0] or die "$ARGV[0]: $!\n";
               binmode FH;
               <FH>;
             };

#---------------------------------
# Process ELF identification data
#---------------------------------
my @ident = unpack "C16", substr $elf, 0, 16;

#-----------------------------
# Is this really an ELF file?
#-----------------------------
unless ($ident[0] == 0x7F && pack("C*", @ident[1..3]) eq 'ELF')
  { die "not an ELF file\n" }

#-----------------------------
# Check ELF class (32/64-Bit)
#-----------------------------
if ($ident[EI_CLASS] == 0) { die "invalid ELF class ($ident[EI_CLASS])\n" }
if ($ident[EI_CLASS] > 2) { die "unsupported ELF class ($ident[EI_CLASS])\n" }
my $class = $ident[EI_CLASS] == 1 ? 'Elf32' : 'Elf64';

#-------------------------------------------
# Check Byte Order (BigEndian/LittleEndian)
#-------------------------------------------
if ($ident[EI_DATA] == 0) { die "invalid data encoding ($ident[EI_DATA])\n" }
if ($ident[EI_DATA] > 2) { die "unsupported data encoding ($ident[EI_DATA])\n" }
$ep->ByteOrder($ident[EI_DATA] == 1 ? 'LittleEndian' : 'BigEndian');

sub get
{
  my($type, $off, $len) = @_;
  $ep->unpack("$class\_$type", @_ > 2 ? substr $elf, $off, $len
                                      : substr $elf, $off);
}

#---------------------------------------------------
# Unpack ELF header and section header string table
#---------------------------------------------------
my $header = get('Ehdr', 0);
my $shstrtab = get('Shdr', $header->{e_shoff} +
                           $header->{e_shstrndx}*$header->{e_shentsize});

print Data::Dumper->Dump([$header], ["*$class\_Ehdr"]) if $opt{debug};

#----------------------------
# Get Name from String Table
#----------------------------
sub get_name
{
  my($tab, $off) = @_;
  return unpack "Z*", substr $elf, $tab->{sh_offset} + $off;
}

#--------------------------
# Read all program headers
#--------------------------
for my $ix (0 .. $header->{e_phnum}-1) {
  my $phdr = get('Phdr', $header->{e_phoff} + $ix*$header->{e_phentsize});
  print Data::Dumper->Dump([$phdr], ["*$class\_Phdr"]) if $opt{debug};
}

#--------------------------
# Read all section headers
#--------------------------
my %section;  # for lookup by section name
my @section;  # for lookup by section index

for my $ix (0 .. $header->{e_shnum}-1) {
  my $shdr = get('Shdr', $header->{e_shoff} + $ix*$header->{e_shentsize});
  print Data::Dumper->Dump([$shdr], ["*$class\_Shdr"]) if $opt{debug};
  $section{get_name($shstrtab, $shdr->{sh_name})} = $shdr;
  push @section, $shdr;
}

#-----------------------------------
# Get Section Name by Section Index
#-----------------------------------
sub get_section_name
{
  my $sec = shift;
  if ($sec == 0 || $sec >= 0xff00) {
    my %res = (0 => 'SHN_UNDEF', 0xfff1 => 'SHN_ABS', 0xfff2 => 'SHN_COMMON');
    return $res{$sec} || sprintf "reserved section 0x%04X", $sec;
  }
  return $sec < @section ? get_name($shstrtab, $section[$sec]{sh_name})
                         : "invalid section $sec";
}

#--------------------------
# Print Header Information
#--------------------------
if ($opt{info}) {
  printf "Byte Order: %s\n", $ep->ByteOrder;
  printf "ELF Class : %s\n", $class;
  printf "ELF Type  : %s\n", $header->{e_type};
  printf "Machine   : %s\n", $header->{e_machine};
}

#------------------------
# Print List Of Sections
#------------------------
if ($opt{list}) {
  printf "%-3s  %-38s  %-13s  %-9s  %-9s\n%s\n",
         'Idx', 'Section', 'Type', 'Offset', 'Size', '-'x80;
  for my $ix (0 .. $#section) {
    my $sh = $section[$ix];
    printf "%3d  %-38s  %-13s  %9d  %9d\n",
            $ix,
                 get_name($shstrtab, $sh->{sh_name}),
                        $sh->{sh_type},
                               $sh->{sh_offset},
                                    $sh->{sh_size};
  }
}

#--------------------
# Print Symbol Table
#--------------------
if ($opt{symbols}) {
  my $symtab = $section{'.symtab'} or die "got no symbol table\n";
  my $strtab = $section{'.strtab'} or die "got no symbol string table\n";

  my @sym = get('Sym', $symtab->{sh_offset}, $symtab->{sh_size});

  printf "%-6s  %-30s  %-9s  %-9s  %-11s  %-11s  %-30s\n%s\n",
         'Index', 'Symbol', 'Value', 'Size', 'Bind', 'Type', 'Section', '-'x120;

  for my $ix (0 .. $#sym) {
    my $s = $sym[$ix];

    print Data::Dumper->Dump([$s], ['*sym']) if $opt{debug};

    printf "%6d  %-30s  %9d  %9d  %-11s  %-11s  %-30s\n",
            $ix,
                 get_name($strtab, $s->{st_name}),
                        $s->{st_value},
                             $s->{st_size},
                                  $s->{st_info}{sti_bind},
                                         $s->{st_info}{sti_type},
                                                get_section_name($s->{st_shndx});
  }
}

#-------------------------
# Write Section to stdout
#-------------------------
if ($opt{section}) {
  my $sec = $opt{section} =~ /^\d+$/ ? $section[$opt{section}]
                                     : $section{$opt{section}};

  die "no such section ($opt{section})\n" unless defined $sec;

  binmode STDOUT;

  print substr $elf, $sec->{sh_offset}, $sec->{sh_size};
}

exit;

###############################################################################
#
# This routine contains the ELF data structures and was generated using:
#
#   perl -MConvert::Binary::C -e'print Convert::Binary::C->new(%{require \
#                 "devel/gcc-config.pl"})->parse_file("elf.h")->sourcify'
#
###############################################################################

sub elf_header
{
  return <<'ENDC';
/* typedef predeclarations */

typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
typedef long long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;
typedef signed char int_least8_t;
typedef short int int_least16_t;
typedef int int_least32_t;
typedef long long int int_least64_t;
typedef unsigned char uint_least8_t;
typedef unsigned short int uint_least16_t;
typedef unsigned int uint_least32_t;
typedef unsigned long long int uint_least64_t;
typedef signed char int_fast8_t;
typedef int int_fast16_t;
typedef int int_fast32_t;
typedef long long int int_fast64_t;
typedef unsigned char uint_fast8_t;
typedef unsigned int uint_fast16_t;
typedef unsigned int uint_fast32_t;
typedef unsigned long long int uint_fast64_t;
typedef int intptr_t;
typedef unsigned int uintptr_t;
typedef long long int intmax_t;
typedef unsigned long long int uintmax_t;


/* typedefs */

typedef uint16_t Elf32_Half;

typedef uint16_t Elf64_Half;

typedef uint32_t Elf32_Word;

typedef int32_t Elf32_Sword;

typedef uint32_t Elf64_Word;

typedef int32_t Elf64_Sword;

typedef uint64_t Elf32_Xword;

typedef int64_t Elf32_Sxword;

typedef uint64_t Elf64_Xword;

typedef int64_t Elf64_Sxword;

typedef uint32_t Elf32_Addr;

typedef uint64_t Elf64_Addr;

typedef uint32_t Elf32_Off;

typedef uint64_t Elf64_Off;

typedef uint16_t Elf32_Section;

typedef uint16_t Elf64_Section;

typedef Elf32_Half Elf32_Versym;

typedef Elf64_Half Elf64_Versym;

typedef struct
{
	unsigned char e_ident[16];
	Elf32_Half e_type;
	Elf32_Half e_machine;
	Elf32_Word e_version;
	Elf32_Addr e_entry;
	Elf32_Off e_phoff;
	Elf32_Off e_shoff;
	Elf32_Word e_flags;
	Elf32_Half e_ehsize;
	Elf32_Half e_phentsize;
	Elf32_Half e_phnum;
	Elf32_Half e_shentsize;
	Elf32_Half e_shnum;
	Elf32_Half e_shstrndx;
} Elf32_Ehdr;

typedef struct
{
	unsigned char e_ident[16];
	Elf64_Half e_type;
	Elf64_Half e_machine;
	Elf64_Word e_version;
	Elf64_Addr e_entry;
	Elf64_Off e_phoff;
	Elf64_Off e_shoff;
	Elf64_Word e_flags;
	Elf64_Half e_ehsize;
	Elf64_Half e_phentsize;
	Elf64_Half e_phnum;
	Elf64_Half e_shentsize;
	Elf64_Half e_shnum;
	Elf64_Half e_shstrndx;
} Elf64_Ehdr;

typedef struct
{
	Elf32_Word sh_name;
	Elf32_Word sh_type;
	Elf32_Word sh_flags;
	Elf32_Addr sh_addr;
	Elf32_Off sh_offset;
	Elf32_Word sh_size;
	Elf32_Word sh_link;
	Elf32_Word sh_info;
	Elf32_Word sh_addralign;
	Elf32_Word sh_entsize;
} Elf32_Shdr;

typedef struct
{
	Elf64_Word sh_name;
	Elf64_Word sh_type;
	Elf64_Xword sh_flags;
	Elf64_Addr sh_addr;
	Elf64_Off sh_offset;
	Elf64_Xword sh_size;
	Elf64_Word sh_link;
	Elf64_Word sh_info;
	Elf64_Xword sh_addralign;
	Elf64_Xword sh_entsize;
} Elf64_Shdr;

typedef struct
{
	Elf32_Word st_name;
	Elf32_Addr st_value;
	Elf32_Word st_size;
	unsigned char st_info;
	unsigned char st_other;
	Elf32_Section st_shndx;
} Elf32_Sym;

typedef struct
{
	Elf64_Word st_name;
	unsigned char st_info;
	unsigned char st_other;
	Elf64_Section st_shndx;
	Elf64_Addr st_value;
	Elf64_Xword st_size;
} Elf64_Sym;

typedef struct
{
	Elf32_Half si_boundto;
	Elf32_Half si_flags;
} Elf32_Syminfo;

typedef struct
{
	Elf64_Half si_boundto;
	Elf64_Half si_flags;
} Elf64_Syminfo;

typedef struct
{
	Elf32_Addr r_offset;
	Elf32_Word r_info;
} Elf32_Rel;

typedef struct
{
	Elf64_Addr r_offset;
	Elf64_Xword r_info;
} Elf64_Rel;

typedef struct
{
	Elf32_Addr r_offset;
	Elf32_Word r_info;
	Elf32_Sword r_addend;
} Elf32_Rela;

typedef struct
{
	Elf64_Addr r_offset;
	Elf64_Xword r_info;
	Elf64_Sxword r_addend;
} Elf64_Rela;

typedef struct
{
	Elf32_Word p_type;
	Elf32_Off p_offset;
	Elf32_Addr p_vaddr;
	Elf32_Addr p_paddr;
	Elf32_Word p_filesz;
	Elf32_Word p_memsz;
	Elf32_Word p_flags;
	Elf32_Word p_align;
} Elf32_Phdr;

typedef struct
{
	Elf64_Word p_type;
	Elf64_Word p_flags;
	Elf64_Off p_offset;
	Elf64_Addr p_vaddr;
	Elf64_Addr p_paddr;
	Elf64_Xword p_filesz;
	Elf64_Xword p_memsz;
	Elf64_Xword p_align;
} Elf64_Phdr;

typedef struct
{
	Elf32_Sword d_tag;
	union
	{
		Elf32_Word d_val;
		Elf32_Addr d_ptr;
	} d_un;
} Elf32_Dyn;

typedef struct
{
	Elf64_Sxword d_tag;
	union
	{
		Elf64_Xword d_val;
		Elf64_Addr d_ptr;
	} d_un;
} Elf64_Dyn;

typedef struct
{
	Elf32_Half vd_version;
	Elf32_Half vd_flags;
	Elf32_Half vd_ndx;
	Elf32_Half vd_cnt;
	Elf32_Word vd_hash;
	Elf32_Word vd_aux;
	Elf32_Word vd_next;
} Elf32_Verdef;

typedef struct
{
	Elf64_Half vd_version;
	Elf64_Half vd_flags;
	Elf64_Half vd_ndx;
	Elf64_Half vd_cnt;
	Elf64_Word vd_hash;
	Elf64_Word vd_aux;
	Elf64_Word vd_next;
} Elf64_Verdef;

typedef struct
{
	Elf32_Word vda_name;
	Elf32_Word vda_next;
} Elf32_Verdaux;

typedef struct
{
	Elf64_Word vda_name;
	Elf64_Word vda_next;
} Elf64_Verdaux;

typedef struct
{
	Elf32_Half vn_version;
	Elf32_Half vn_cnt;
	Elf32_Word vn_file;
	Elf32_Word vn_aux;
	Elf32_Word vn_next;
} Elf32_Verneed;

typedef struct
{
	Elf64_Half vn_version;
	Elf64_Half vn_cnt;
	Elf64_Word vn_file;
	Elf64_Word vn_aux;
	Elf64_Word vn_next;
} Elf64_Verneed;

typedef struct
{
	Elf32_Word vna_hash;
	Elf32_Half vna_flags;
	Elf32_Half vna_other;
	Elf32_Word vna_name;
	Elf32_Word vna_next;
} Elf32_Vernaux;

typedef struct
{
	Elf64_Word vna_hash;
	Elf64_Half vna_flags;
	Elf64_Half vna_other;
	Elf64_Word vna_name;
	Elf64_Word vna_next;
} Elf64_Vernaux;

typedef struct
{
	int a_type;
	union
	{
		long int a_val;
		void *a_ptr;
		void *a_fcn;
	} a_un;
} Elf32_auxv_t;

typedef struct
{
	long int a_type;
	union
	{
		long int a_val;
		void *a_ptr;
		void *a_fcn;
	} a_un;
} Elf64_auxv_t;

typedef struct
{
	Elf32_Word n_namesz;
	Elf32_Word n_descsz;
	Elf32_Word n_type;
} Elf32_Nhdr;

typedef struct
{
	Elf64_Word n_namesz;
	Elf64_Word n_descsz;
	Elf64_Word n_type;
} Elf64_Nhdr;

typedef struct
{
	Elf32_Xword m_value;
	Elf32_Word m_info;
	Elf32_Word m_poffset;
	Elf32_Half m_repeat;
	Elf32_Half m_stride;
} Elf32_Move;

typedef struct
{
	Elf64_Xword m_value;
	Elf64_Xword m_info;
	Elf64_Xword m_poffset;
	Elf64_Half m_repeat;
	Elf64_Half m_stride;
} Elf64_Move;

typedef union
{
	struct
	{
		Elf32_Word gt_current_g_value;
		Elf32_Word gt_unused;
	} gt_header;
	struct
	{
		Elf32_Word gt_g_value;
		Elf32_Word gt_bytes;
	} gt_entry;
} Elf32_gptab;

typedef struct
{
	Elf32_Word ri_gprmask;
	Elf32_Word ri_cprmask[4];
	Elf32_Sword ri_gp_value;
} Elf32_RegInfo;

typedef struct
{
	unsigned char kind;
	unsigned char size;
	Elf32_Section section;
	Elf32_Word info;
} Elf_Options;

typedef struct
{
	Elf32_Word hwp_flags1;
	Elf32_Word hwp_flags2;
} Elf_Options_Hw;

typedef struct
{
	Elf32_Word l_name;
	Elf32_Word l_time_stamp;
	Elf32_Word l_checksum;
	Elf32_Word l_version;
	Elf32_Word l_flags;
} Elf32_Lib;

typedef struct
{
	Elf64_Word l_name;
	Elf64_Word l_time_stamp;
	Elf64_Word l_checksum;
	Elf64_Word l_version;
	Elf64_Word l_flags;
} Elf64_Lib;

typedef Elf32_Addr Elf32_Conflict;
ENDC
}

__END__

=head1 NAME

elf.pl - Read ELF Files

=head1 SYNOPSIS

elf.pl {I<options>} elf-file

I<options>:

  -i  --info           print information
  -l  --list           print section list
      --symbols        print symbol table
  -s  --section NAME   write section to stdout
      --debug          enable debug output

example:

  elf.pl -il C.o

=cut
