Sys-Export

 view release on metacpan or  search on metacpan

lib/Sys/Export/ELF.pm  view on Meta::CPAN

our @elf_header_fields= qw( type machine version entry_point segment_table_ofs section_table_ofs
      flags elf_header_len segment_header_elem_len segment_count
      section_header_elem_len section_count section_name_string_table_idx );
our @elf_header_packstr= (
   'a16 v v V V V V V v v v v v v', # 32-bit LE
   'a16 n n N N N N N n n n n n n', # 32-bit BE
   'a16 v v V Q< Q< Q< V v v v v v v', # 64-bit LE
   'a16 n n N Q> Q> Q> N n n n n n n', # 64-bit BE
);
our @segment_header_len= ( 32, 32, 56, 56 );
# 'flags' moves depending on 32 vs 64 bit, so changing the pack string isn't enough
our @segment_header_fields= (
   [ qw( type offset virt_addr phys_addr filesize memsize flags align ) ],
   [ qw( type offset virt_addr phys_addr filesize memsize flags align ) ],
   [ qw( type flags offset virt_addr phys_addr filesize memsize align ) ],
   [ qw( type flags offset virt_addr phys_addr filesize memsize align ) ],
);
our @segment_header_packstr= (
   'V V V V V V V V',
   'N N N N N N N N',
   'V V Q< Q< Q< Q< Q< Q<',
   'N N Q> Q> Q> Q> Q> Q>',
);
our @segment_header_type= _make_enum qw( NULL LOAD DYNAMIC INTERP NOTE SHLIB PHDR TLS );

our @section_header_len= ( 40, 40, 64, 64 );
our @section_header_fields= qw( name type flags addr offset size link info align entry_size );
our @section_header_packstr= (
   'V V V V V V V V V V',
   'N N N N N N N N N N',
   'V V Q< Q< Q< Q< V V Q< Q<',
   'N N Q> Q> Q> Q> N N Q> Q>',
);

our @dynamic_link_entry_len= ( 8, 8, 16, 16 );
our @dynamic_link_entry_fields= qw( tag val );
our @dynamic_link_entry_packstr= (
   'V V',
   'N N',
   'Q< Q<',
   'Q> Q>',
);
our @dynamic_link_entry_tag= _make_enum qw( NULL NEEDED PLTRELSZ PLTGOT HASH STRTAB SYMTAB RELA
   RELASZ RELAENT STRSZ SYMENT INIT FINI SONAME RPATH SYMBOLIC REL RELSZ RELENT PLTREL DEBUG
   TEXTREL JMPREL BIND_NOW INIT_ARRAY FINI_ARRAY INIT_ARRAYSZ FINI_ARRAYSZ RUNPATH FLAGS
   ENCODING PREINIT_ARRAY PREINIT_ARRAYSZ SYMTAB_SHNDX RELRSZ RELR RELRENT NUM );

our @symbol_table_fields= (
   [qw( name value size info other shndx )],
   [qw( name value size info other shndx )],
   [qw( name info other shndx value size )],
   [qw( name info other shndx value size )],
);
our @symbol_table_packstr= (
   'V V V C C v',
   'N N N C C n',
   'V C C v Q< Q<',
   'N C C n Q> Q>',
);

our @relocation_fields= qw( offset info );
our @relocation_packstr= (
   'V V',
   'N N',
   'Q< Q<',
   'Q> Q>',
);

our @relocation_addend_fields= qw( offset info addend );
our @relocation_addend_packstr= (
   'V V V',
   'N N N',
   'Q< Q< Q<',
   'Q> Q> Q>',
);

sub _strz_from_offset {
   return undef unless 0 <= $_[1] && $_[1] < length $_[0];
   pos $_[0] = $_[1];
   $_[0] =~ /\G([^\0]*)/? $1 : undef;
}


sub unpack {
   # This doesn't copy $_[0] into a variable because it might be a memory-map
   my %elf;

   # Start with the encoding-independent fields
   @elf{@elf_common_header_fields}= _unpack($elf_common_header_packstr, $_[0]);
   $elf{magic} eq "\x7FELF" or return undef;
   die "Unsupported 'class'" unless 1 <= $elf{class} && $elf{class} <= 2;
   die "Unsupported 'data'" unless 1 <= $elf{data} && $elf{data} <= 2;
   my $encoding_idx= ($elf{class}-1)*2 + ($elf{data}-1);

   # Now decode the endian and bit-length-varying fields
   (undef, @elf{@elf_header_fields})= _unpack $elf_header_packstr[$encoding_idx], $_[0];
   my $lim= length $_[0];
   
   # parse segments
   my @segments;
   # sanity check on table size
   my $elem_len= $elf{segment_header_elem_len};
   if ($elf{segment_count} > 0) {
      $elf{segment_table_ofs} < $lim
         or croak "Segment table beyond end of file";
      $elem_len >= $segment_header_len[$encoding_idx]
         or croak "Segment records are shorter than expected";
      $elf{segment_count} <= (($lim - $elf{segment_table_ofs}) / $elem_len)
         or croak "Segment table extends past end of file";

      for (my $i= 0; $i < $elf{segment_count}; $i++) {
         my $ofs= $elf{segment_table_ofs} + $i * $elem_len;
         my %segment;
         @segment{@{$segment_header_fields[$encoding_idx]}}
            = _unpack $segment_header_packstr[$encoding_idx],
                  substr($_[0], $ofs, $elem_len);
         $segment{type}= $segment_header_type[$segment{type}]
            if $segment{type} > 0 && $segment{type} < @segment_header_type;
         push @segments, \%segment;
      }
   }
   $elf{segments}= \@segments;

   $elem_len= $elf{section_header_elem_len};
   my @sections;
   my $dynamic_section;
   if ($elf{section_count} > 0) {
      $elf{section_table_ofs} < $lim
         or croak "Section table beyond end of file";
      $elem_len >= $section_header_len[$encoding_idx]



( run in 1.226 second using v1.01-cache-2.11-cpan-71847e10f99 )