:mod:`libelf` -- classes for ELF and ar inspection
==============================================================================
.. module:: libelf
    :synopsis: classes for interacting with ELF and ar files

The :class:`Library` class provides interaction with ELF files. To open a file 
from a filename, simply type::
    
    from pylibelf import libelf
    lib = libelf.Library("/bin/bash")
    print lib

This will print out all the gory details of the library. If you don't want
this behaviour, you can set the ``sanestr`` setting to ``False`` 
(see :ref:`settings` for details), or use ``repr()``.

.. function:: ldd(path, cwd=os.curdir, library_path=[], skip_missing=False)

    :platform: Unix

    Like ldd, return a list of libraries that an executable or shared library
    depends on.

    :param path: path to the executable or library
    :param cwd: if the cwd is specified in the RPATH of the executable or 
        library, or specified by LD_LIBRARY_PATH (e.g. 'foo:bar:'), use cwd
        as the cwd
    :param library_path: path of library directories to search after RPATH
        but before LD_LIBRARY_PATH
    :param skip_missing: if True, don't raise :class:`LocateError` when a
        dependency couldn't be found
    


.. class:: Library(path|fd[, write=False[, create=False[, elfclass=ELFCLASSNONE]]])

    Open an ELF file from a path or fd.
    
    :param path: path to the ELF object file to open. For Ar file see the 
        :class:`Ar` class.
    :param fd: file descriptor of the ELF file to open
    :param write: specifies whether to open the ELF file for writing also
    :param create: if true, create a new ELF file at ``path``
    :param elfclass: the class the ELF file should have

    .. note::

        Write support is currently experimental and may or may not bite you
        in the buttocks.

    .. attribute:: filename

        Filename of the object, if ``path`` was given to the constructor.

    .. attribute:: mode

        Mode the ELF file is opened in.

    .. attribute:: type

        Type of ELF file (``ET_EXEC``, ``ET_DYN``, etc).

    .. attribute:: kind

        Kind of file (``ELF_K_ELF``, ``ELF_K_COFF``, ``ELF_K_AR``).

    .. attribute:: elfclass

        The class of the ELF file (e.g. ``ELFCLASS32``, ``ELFCLASS64``).

    .. attribute:: ordering
        
        Byte ordering of the ELF file (e.g. ``ELFDATA2LSB``, ``ELFDATA2MSB``).

    .. attribute:: os_abi

        OS/ABI identification.

    .. attribute:: abi_version

        The version of the ABI it wants.

    .. attribute:: machine

        The machine architecture the ELF file was compiled for 
        (e.g. ``EM_386``, ``EM_X86_64``).

    .. attribute:: entrypoint

        The entrypoint of the program.

    .. attribute:: segments

        The segments in the object file.

    .. attribute:: sections

        The sections in the object file.

    .. attribute:: strtab
        
        The string table section holding the section names.

    .. attribute:: symtab

        The symbol table section of the object file (``SHT_SYMTAB``).
        Set for relocatable object files.

    .. attribute:: dynsym
    
        The symbol table section of the object file (``SHT_DYNSYM``).
        Set for shared libraries and executables.

    .. attribute:: dynamic_section
        
        The dynamic section of the object file (``SHT_DYNAMIC``).

    .. attribute:: dependencies

        Direct dependencies of this object file.

    .. attribute:: soname

        The name of the shared library.

    .. method:: findsection(\*\*kwargs)

        Convenience method, like :class:`find` for sections.

    .. method:: findsegment(\*\*kwargs)

        Convenience method, like :class:`find` for segments.

    .. method:: save([path])

        Write the ELF representation to the path given in the constructor, 
        or to ``path`` if supplied as an argument.

    .. method:: close()
        
        Explicitly close the library (this would otherwise 
        happen in the deconstructor).

        
Example::

    >>> from pylibelf import libelf, elf, elf_constants
    >>> lib = libelf.Library('/bin/ls')
    >>> print lib.findsection(name='.interp')
    Section(name:      '.interp'                                                                                                                                 
            type:      Type(SHT_PROGBITS, 'Program data')                                                                                                        
            flags:     0x02                                                                                                                                      
            address:   0x400238                                                                                                                                  
            offset:    0x238                                                                                                                                     
            link:      0x00                                                                                                                                      
            info:      0x00                                                                                                                                      
            addralign: 0x01                                                                                                                                      
            entsize:   0x00                                                                                                                                      
            data:      SectionData(type:    Type(ELF_T_BYTE, 0)                                                                                                  
                                   version: 0x01                                                                                                                 
                                   data:    '/lib64/ld-linux-x86-64.so.2\x00'                                                                                    
                                   size:    0x1c))                                                                                                               
    >>> elf.pretty_print(elf.findall(lib.segments, type=elf_constants.PT_LOAD))                                                                            
    [Segment(type:             Type(PT_LOAD, 'Loadable program segment')                                                                                         
             readable:         0x01                                                                                                                              
             writable:         0x00                                                                                                                              
             executable:       0x01                                                                                                                              
             alignment:        Type('2**21')                                                                                                                     
             offset:           0x00                                                                                                                              
             virtual_address:  0x400000                                                                                                                          
             physical_address: 0x400000                                                                                                                          
             filesize:         0x1aa84                                                                                                                           
             memsize:          0x1aa84                                                                                                                           
             section_names:    ['.interp'                                                                                                                        
                                '.note.ABI-tag'                                                                                                                  
                                '.note.gnu.build-id'                                                                                                             
                                '.hash'                                                                                                                          
                                '.gnu.hash'                                                                                                                      
                                '.dynsym'                                                                                                                        
                                '.dynstr'                                                                                                                        
                                '.gnu.version'                                                                                                                   
                                '.gnu.version_r'                                                                                                                 
                                '.rela.dyn'                                                                                                                      
                                '.rela.plt'                                                                                                                      
                                '.init'                                                                                                                          
                                '.plt'                                                                                                                           
                                '.text'                                                                                                                          
                                '.fini'                                                                                                                          
                                '.rodata'                                                                                                                        
                                '.eh_frame_hdr'                                                                                                                  
                                '.eh_frame'])                                                                                                                    
     Segment(type:             Type(PT_LOAD, 'Loadable program segment')                                                                                         
             readable:         0x01                                                                                                                              
             writable:         0x01                                                                                                                              
             executable:       0x00                                                                                                                              
             alignment:        Type('2**21')                                                                                                                     
             offset:           0x1ade0                                                                                                                           
             virtual_address:  0x61ade0                                                                                                                          
             physical_address: 0x61ade0                                                                                                                          
             filesize:         0x750                                                                                                                             
             memsize:          0x14a0                                                                                                                            
             section_names:    ['.ctors'                                                                                                                         
                                '.dtors'                                                                                                                         
                                '.jcr'                                                                                                                           
                                '.dynamic'                                                                                                                       
                                '.got'                                                                                                                           
                                '.got.plt'                                                                                                                       
                                '.data'                                                                                                                          
                                '.bss'])]
        
.. class:: Segment(\*, sections, type=PT_NOTE, flags=PF_R, alignment=0, offset=-1, virtual_address=0, physical_address=0, filesize=0, memsize=0)
    
    Represents an ELF segment. Attributes are as listed in the constructor,
    they correspond to the p_* attributes of the ELF segment header.
    Additional attributes are ``readable``, ``writable`` and ``executable``.


.. class:: Section(\*, name, data=None, type, flags=0, address=0, offset=0, size=0, link=0, info=0, addralign=0, entsize=0)

    Represents an ELF section. Attributes are as listed in the constructor,
    they correspond to the sh_* attributes of the ELF section header.

    .. method:: issym()

        Indicates whether this section is a symbol table.


.. class:: SymbolTable(symbols[, \*\*kwargs])
    
    Extends :class:`Section`. ``symbols`` should be a list of :class:`Symbol`.
    ``kwargs`` is passed to the parent constructor.

    .. attribute:: symbols

        The list of symbols in the section.

    .. attribute:: strtab

        The string table holding the names of the symbols

    .. method:: findsymbol(name[, \*\*kwargs])

        Find a symbol with name ``name`` and optionally attributes specified by
        ``kwargs``.


.. class:: StringTable(strings[, \*\*kwargs])

    Extends :class:`Section`. ``strings`` should be a list of strings.

    .. attribute:: strings

        The list of strings that are in the string table.

    .. method:: add_strings(\*newstrings)

        Add a bunch of strings to the string table. This method takes care of
        substrings (e.g. serialize ['spamham', 'ham'] as '\\0spamham\\0' instead
        of '\\0spamham\\0ham\\0').

    .. method:: string_from_offset(offset)

        Return the string given the offset into the section data.

.. class:: RelocationSection(relocations[, \*\*kwargs])

    Extends :class:`Section`. ``strings`` should be a list of 
    :class:`Relocation`.

    
    .. attribute:: relocations

        The relocations specified by the section.

    .. attribute:: relocatee

        The section the relocations apply to.

    .. attribute:: symtab

        The associated symbol table.

.. class:: DynamicSection(dyns[, \*\*kwargs])

    Extends :class:`Section`. ``dyns`` should be a list of
    :class:`Dyn`.

    .. attribute:: dyns

        The list of entries with dynamic linking information.

    .. attribute:: strtab

        The string table associated with the dynamic section.

    .. attribute:: rpath

        List of paths that the library specifies to look for for dependencies.

    .. attribute:: dependencies

    Equivalent to :class:`Library.dependencies`

.. class:: SectionData(data[, \*, type, alignment])
    
    Represents the data of a section, it is the ``data`` attribute of
    a :class:`Section`.

    .. attribute:: data

        The data of the section as a byte string.

    .. attribute:: type

        The type of the items in the data (e.g. ``ELF_T_BYTE``, 
        ``ELF_T_DYN``, etc)
    
    .. attribute:: alignment

        Alignment used by the section.

.. class:: Symbol([\*, name, value, size, binding=STB_GLOBAL, type=STT_NOTYPE, other, shndx])
    
    Represents a single symbol in a symbol table. The constructor arguments
    are attributes of the instance.

    .. method:: get_related_section(lib)
        
        Get the section the symbol was specified in relation to. ``lib`` is the
        :class:`Library` the symbol was found in.

    .. method:: set_related_section(lib, section)

.. class:: Relocation(machine, offset, symindex, type)

    Represents a single relocation. ``machine`` should be one of the 
    ``EM_*`` constants.
    ``offset``, ``symindex`` and ``type`` are instance attributes.
    ``type`` can have values specified by the ``R_`` constants (constants
    should be chosen according to ``machine``).

    .. attribute:: info
        
        The r_info attribute of the associated Elfxx_Rel structure.

.. class:: RelocationAddend(..., addend)

    Like :class:`Relocation` but with an addend.

.. class:: Dyn(tag, value)

    An entry in the dynamic section. ``tag`` and ``value`` are instance attributes,
    and can have values specified by the flags ``DT_`` and ``DF_`` respectively.

    .. method:: ispointer()

        Indicates whether `self.value` should be treated as a pointer.

.. class:: Ar(path)

    Open an ar file for reading.

    .. attribute:: path
    
        Path to the ar file.
        
    .. attribute:: headers
    
        List of :class:`ArHeader` founds in the ar file.
    
    .. attribute:: libs
    
        List of :class:`ArLibrary` found in the ar file.
    
    .. attribute:: symbols

        Symbol table of the ar file.

    .. method:: lib_from_name(symbolname)
        
        Get the ArLibrary object associated with symbol name ``symbolname``.

    .. method:: lib_from_sym(symbol)

        Get the ArLibrary object associated with symbol ``symbol``.

    .. method:: lib_from_offset(offset)

        Get the ArLibrary object associated with offset ``offset``.

.. class:: ArLibrary()
    
    An ArLibrary is like a :class:`Library` with some extra functionality.

    .. attribute:: header

        The :class:`ArHeader` that has some metadata of this library.

    .. attribute:: ar

        The :class:`Ar` file holding this library.

    .. attribute:: extracted

        Tells us whether we extracted this library using the :class:`extract`
        method.

    .. method:: extract(path)

        Save the library to a file specified by ``path``. After extraction
        addtional changes can be saved using the potentially broken
        :class:`save` method.

.. class:: ArHeader()

    The header in the ar file holding metadata on a contained library.
    Attributes are ``name, ``date``, ``uid``, ``gid``, ``mode``, 
    ``dataoffset``, ``size``.

.. class:: ArSymbol()
    
    A symbol in the ar file. Attribute are ``name``, ``offset`` and
    ``hash``.

Example::
    
    >>> from pylibelf import libelf
    >>> ar = libelf.Ar('/usr/lib/libpython2.6.a')
    >>> print ar.libs[0].header                                                                                                                                  
    ArHeader(name:       'getbuildinfo.o'                                                                                                                        
             date:       Type('Fri Apr 16 16:42:48 2010')                                                                                                        
             uid:        0x00                                                                                                                                    
             gid:        0x00                                                                                                                                    
             mode:       0x81a4                                                                                                                                  
             offset:     0x6b9a                                                                                                                                  
             dataoffset: 0x6bd6                                                                                                                                  
             size:       0x8a0)                                                                                                                                  
    >>> print ar.libs[0].symtab                                                                                                                                  
    SymbolTable(name:      '.symtab'                                                                                                                             
                type:      Type(SHT_SYMTAB, 'Symbol table')                                                                                                      
                flags:     0x00                                                                                                                                  
                address:   0x00                                                                                                                                  
                offset:    0x568                                                                                                                                 
                link:      0x0d                                                                                                                                  
                info:      0x0b                                                                                                                                  
                addralign: 0x08                                                                                                                                  
                entsize:   0x18                                                                                                                                  
                data:      SectionData(type:    Type(ELF_T_SYM, 11)                                                                                              
                                       version: 0x01                                                                                                             
                                       data:    '\x00\x00\x00\x00\x00\x00\x00\x00\x ...'                                                                         
                                       size:    0x180)                                                                                                           
                symbols:   [Symbol(name:    ''                                                                                                                   
                                   value:   0x00                                                                                                                 
                                   size:    0x00                                                                                                                 
                                   binding: Type(STB_LOCAL, 'Local symbol')                                                                                      
                                   type:    Type(STT_NOTYPE, 'Symbol type is unspecified')                                                                       
                                   shndx:   0x00)                                                                                                                
                            
                            ...                                                                                                                
                            
                            Symbol(name:    'PyOS_snprintf'                                                                                                      
                                   value:   0x00                                                                                                                 
                                   size:    0x00                                                                                                                 
                                   binding: Type(STB_GLOBAL, 'Global symbol')                                                                                    
                                   type:    Type(STT_NOTYPE, 'Symbol type is unspecified')                                                                       
                                   shndx:   0x00)])

Exceptions
----------
.. exception:: ELFError
    
    Raised when any ELF related error occurs.

.. exception:: LocateError

    Raised when :class:`ldd` was not able to locate a shared library.

