# Volatility
# Copyright (C) 2007-2011 Volatile Systems
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details. 
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA

# ELF64 format: http://downloads.openwatcom.org/ftp/devel/docs/elf-64-gen.pdf

import volatility.obj as obj


elf32_vtypes = {
    'elf32_hdr' : [ 52, {
        'e_ident' : [ 0, ['String', dict(length = 16)]], 
        'e_type' : [ 16, ['Enumeration', dict(target = 'unsigned short', choices = {
            0: 'ET_NONE', 
            1: 'ET_REL', 
            2: 'ET_EXEC', 
            3: 'ET_DYN', 
            4: 'ET_CORE', 
            0xff00: 'ET_LOPROC', 
            0xffff: 'ET_HIPROC'})]],
        'e_machine' : [ 18, ['unsigned short']], 
        'e_version' : [ 20, ['unsigned int']], 
        'e_entry' : [ 24, ['unsigned int']], 
        'e_phoff' : [ 28, ['unsigned int']], 
        'e_shoff' : [ 32, ['unsigned int']], 
        'e_flags' : [ 36, ['unsigned int']], 
        'e_ehsize'    : [ 40, ['unsigned short']], 
        'e_phentsize' : [ 42, ['unsigned short']], 
        'e_phnum'     : [ 44, ['unsigned short']], 
        'e_shentsize' : [ 46, ['unsigned short']], 
        'e_shnum'     : [ 48, ['unsigned short']], 
        'e_shstrndx'  : [ 50, ['unsigned short']], 
        }], 
 
   'elf32_phdr' : [ 32, {
        'p_type' : [ 0, ['Enumeration', dict(target = 'unsigned int', choices = {
            0: 'PT_NULL', 
            1: 'PT_LOAD',
            2: 'PT_DYNAMIC', 
            3: 'PT_INTERP', 
            4: 'PT_NOTE', 
            5: 'PT_SHLIB', 
            6: 'PT_PHDR', 
            7: 'PT_TLS', 
            0x60000000: 'PT_LOOS', 
            0x6fffffff: 'PT_HIOS', 
            0x70000000: 'PT_LOPROC', 
            0x7fffffff: 'PT_HIPROC'})]],
        'p_offset' : [ 4,  ['unsigned int']], 
        'p_vaddr'  : [ 8,  ['unsigned int']], 
        'p_paddr'  : [ 12, ['unsigned int']], 
        'p_filesz' : [ 16, ['unsigned int']], 
        'p_memsz'  : [ 20, ['unsigned int']], 
        'p_flags'  : [ 24, ['unsigned int']], 
        'p_align'  : [ 28, ['unsigned int']], 
        }], 
    
    'elf32_shdr' : [40, { 
        'sh_name'   : [0,  ['unsigned int']],
        'sh_type'   : [4,  ['unsigned int']],
        'sh_flags'  : [8,  ['unsigned int']],
        'sh_addr'   : [12, ['unsigned int']],
        'sh_offset' : [16, ['unsigned int']],
        'sh_size'   : [20, ['unsigned int']],
        'sh_link'   : [24, ['unsigned int']],
        'sh_info'      : [28, ['unsigned int']],
        'sh_addralign' : [32, ['unsigned int']],
        'sh_entsize'   : [36, ['unsigned int']],
        }],

    'elf32_dyn' : [ 8, {
        'd_tag' : [0, ['int']],
        'd_ptr' : [4, ['unsigned int']],
        }],
 
    'elf32_note' : [ 12, {
        'n_namesz' : [ 0, ['unsigned int']], 
        'n_descsz' : [ 4, ['unsigned int']], 
        'n_type' : [ 8, ['unsigned int']], 
         ## FIXME: this must be cast to int() because the base AS (FileAddressSpace) read method doesn't understand NativeType.
         ## Remove the cast after http://code.google.com/p/volatility/issues/detail?id=350 is fixed. 
        'namesz' : [ 12, ['String', dict(length = lambda x : int(x.n_namesz))]], 
        }],
 
    'elf32_link_map' : [0, {
        'l_addr' : [0, ['unsigned int']], 
        'l_name' : [4, ['unsigned int']], 
        'l_ld'   : [8, ['unsigned int']], 
        'l_next' : [12, ['unsigned int']], 
        'l_prev' : [16, ['unsigned int']], 
        }],

    'elf32_sym' : [ 16, {
        'st_name'   : [ 0,  ['unsigned int']],
        'st_value'  : [ 4,  ['unsigned int']],
        'st_size'   : [ 8,  ['unsigned int']],
        'st_info'   : [ 12, ['unsigned char']],
        'st_other'  : [ 13, ['unsigned char']],
        'st_shndx'  : [ 14,  ['unsigned short']],
    }],

    'elf32_rel' : [ 8, {
        'r_offset' : [ 0,  ['unsigned int']],
        'r_info'   : [ 4,  ['unsigned int']],
    }],

    'elf32_rela' : [ 12, {
        'r_offset' : [ 0,  ['unsigned int']],
        'r_info'   : [ 4,  ['unsigned int']],
        'r_addend' : [ 8,  ['int']],
     }],
}

elf64_vtypes = {
    'elf64_hdr' : [ 64, {
        'e_ident' : [ 0, ['String', dict(length = 16)]], 
        'e_type' : [ 16, ['Enumeration', dict(target = 'unsigned short', choices = {
            0: 'ET_NONE', 
            1: 'ET_REL', 
            2: 'ET_EXEC', 
            3: 'ET_DYN', 
            4: 'ET_CORE', 
            0xff00: 'ET_LOPROC', 
            0xffff: 'ET_HIPROC'})]],
        'e_machine' : [ 18, ['unsigned short']], 
        'e_version' : [ 20, ['unsigned int']], 
        'e_entry' : [ 24, ['unsigned long long']], 
        'e_phoff' : [ 32, ['unsigned long long']], 
        'e_shoff' : [ 40, ['unsigned long long']], 
        'e_flags' : [ 48, ['unsigned int']], 
        'e_ehsize'    : [ 52, ['unsigned short']], 
        'e_phentsize' : [ 54, ['unsigned short']], 
        'e_phnum'     : [ 56, ['unsigned short']], 
        'e_shentsize' : [ 58, ['unsigned short']], 
        'e_shnum'     : [ 60, ['unsigned short']], 
        'e_shstrndx'  : [ 62, ['unsigned short']], 
        }],
 
    'elf64_phdr' : [ 56, {
        'p_type' : [ 0, ['Enumeration', dict(target = 'unsigned int', choices = {
            0: 'PT_NULL', 
            1: 'PT_LOAD',
            2: 'PT_DYNAMIC', 
            3: 'PT_INTERP', 
            4: 'PT_NOTE', 
            5: 'PT_SHLIB', 
            6: 'PT_PHDR', 
            7: 'PT_TLS', 
            0x60000000: 'PT_LOOS', 
            0x6fffffff: 'PT_HIOS', 
            0x70000000: 'PT_LOPROC', 
            0x7fffffff: 'PT_HIPROC'})]],
        'p_flags' : [ 4, ['unsigned int']], 
        'p_offset' : [ 8, ['unsigned long long']], 
        'p_vaddr' : [ 16, ['unsigned long long']], 
        'p_paddr' : [ 24, ['unsigned long long']], 
        'p_filesz' : [ 32, ['unsigned long long']], 
        'p_memsz' : [ 40, ['unsigned long long']], 
        'p_align' : [ 48, ['unsigned long long']], 
        }], 

    'elf64_shdr' : [64, { 
        'sh_name'   : [0,  ['unsigned int']],
        'sh_type'   : [4,  ['unsigned int']],
        'sh_flags'  : [8,  ['unsigned long long']],
        'sh_addr'   : [16, ['unsigned long long']],
        'sh_offset' : [24, ['unsigned long long']],
        'sh_size'   : [32, ['unsigned long long']],
        'sh_link'   : [40, ['unsigned int']],
        'sh_info'      : [44, ['unsigned int']],
        'sh_addralign' : [48, ['unsigned long long']],
        'sh_entsize'   : [56, ['unsigned long long']],
        }],

    'elf64_dyn' : [ 16, {
        'd_tag' : [0, ['long long']],
        'd_ptr' : [8, ['unsigned long long']],
        }],

    'elf64_note' : [ 12, {
        'n_namesz' : [ 0, ['unsigned int']], 
        'n_descsz' : [ 4, ['unsigned int']], 
        'n_type' : [ 8, ['unsigned int']], 
         ## FIXME: this must be cast to int() because the base AS (FileAddressSpace) read method doesn't understand NativeType.
         ## Remove the cast after http://code.google.com/p/volatility/issues/detail?id=350 is fixed. 
        'namesz' : [ 12, ['String', dict(length = lambda x : int(x.n_namesz))]], 
        }],
    
    'elf64_sym' : [ 24 , {
        'st_name'  : [ 0, ['unsigned int']],
        'st_info'  : [ 4, ['unsigned char']],
        'st_other' : [ 5, ['unsigned char']],
        'st_shndx' : [ 6, ['unsigned short']],
        'st_value' : [ 8, ['unsigned long long']],
        'st_size'  : [ 16, ['unsigned long long']],
    }],

    'elf64_link_map' : [0, {
        'l_addr' : [0, ['unsigned long long']], 
        'l_name' : [8, ['unsigned long long']], 
        'l_ld'   : [16, ['unsigned long long']], 
        'l_next' : [24, ['unsigned long long']], 
        'l_prev' : [32, ['unsigned long long']], 
    }],
   
    'elf64_rel' : [ 16, {
        'r_offset' : [ 0,  ['unsigned long long']],
        'r_info'   : [ 8,  ['unsigned long long']],
    }],

    'elf64_rela' : [ 24, {
        'r_offset' : [ 0,  ['unsigned long long']],
        'r_info'   : [ 8,  ['unsigned long long']],
        'r_addend' : [ 16,  ['long long']],
    }],
}

class elf(obj.CType):
    def __init__(self, is_header, name32, name64, theType, offset, vm, name = None, **kwargs):  
        self.name32 = name32
        self.name64 = name64
        self.elf_obj = None

        if is_header:
            self._init_cache(offset, vm)
        else:
            self.size_cache = -39

        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
    
    def is_valid(self):
        return self.size_cache in [32, 64, -39]

    def _init_cache_from_parent(self):
        self.size_cache = self.obj_parent.size_cache
        
        self._make_elf_obj(self.obj_offset, self.obj_vm)

    def _make_elf_obj(self, offset, vm):
        if self.size_cache == 32:
            self.elf_obj = obj.Object(self.name32, offset = offset, vm = vm)
        elif self.size_cache == 64:
            self.elf_obj = obj.Object(self.name64, offset = offset, vm = vm)
        else:
            self.elf_obj = None
        
    def _set_size_cache(self, offset, vm):
        ei_class = obj.Object("unsigned char", offset = offset + 4, vm = vm)
        if ei_class == 1:
            self.size_cache = 32
        elif ei_class == 2:
            self.size_cache = 64
        else:
            self.size_cache = -42

    def _init_cache(self, offset, vm):
        self._set_size_cache(offset, vm)
        self._make_elf_obj(offset, vm) 

    def _get_typename(self, typename):
        if self.size_cache == -39:
            self._init_cache_from_parent()

        if self.size_cache == 32:
            typename = "elf32_" + typename
        else:
            typename = "elf64_" + typename

        return typename

    def __getattr__(self, attr):
        if self.size_cache == -39:
            self._init_cache_from_parent()

        return self.elf_obj.__getattr__(attr)

class elf_hdr(elf):
    """An ELF header"""
    
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        # these are populaed on the first call to symbols()
        self.cached_symtab  = None
        self.cached_strtab  = None
        self.cached_numsyms = 0

        elf.__init__(self, 1, "elf32_hdr", "elf64_hdr", theType, offset, vm, name, **kwargs)    

    def is_valid(self):
        return self.elf_obj != None
        
    def program_headers(self):
        rtname = self._get_typename("phdr")
        rtsize = self.obj_vm.profile.get_obj_size(rtname)

        tname = "elf_phdr"
        
        if self.e_phoff < 0 or self.e_phoff > 1000000:
            return

        # the buffer of headers
        arr_start = self.obj_offset + self.e_phoff

        if self.e_phnum > 128:
            phnum = 128
        else:
            phnum = self.e_phnum

        for i in range(phnum):
            # use the real size
            idx = i * rtsize

            phdr = obj.Object("elf_phdr", offset = arr_start + idx, vm = self.obj_vm, parent = self)
            if phdr.is_valid():
                yield phdr  

    def _section_headers(self):
        rtname = self._get_typename("shdr")
        rtsize = self.obj_vm.profile.get_obj_size(rtname)

        tname = "elf_shdr"
       
        if self.e_shoff < 1:
            arr_start = -1
        else:
            # the buffer of headers
            arr_start = self.obj_offset + self.e_shoff

        return (arr_start, rtsize)

    def section_headers(self):
        (arr_start, rtsize) = self._section_headers()

        if arr_start == -1:
            return

        for i in range(self.e_shnum):
            # use the real size
            idx = i * rtsize

            shdr = obj.Object("elf_shdr", offset = arr_start + idx, vm = self.obj_vm, parent = self)
            if shdr.is_valid():
                yield shdr  

    def _find_symbols_program_headers(self):
        for phdr in self.program_headers():
            if not phdr.is_valid() or str(phdr.p_type) != 'PT_DYNAMIC':
                continue                   
    
            dt_strtab = None
            dt_symtab = None    
            dt_strent = None

            for dsec in phdr.dynamic_sections():
                if dsec.d_tag == 5:
                    dt_strtab = dsec.d_ptr

                elif dsec.d_tag == 6:
                    dt_symtab = dsec.d_ptr

                elif dsec.d_tag == 11:
                    dt_strent = dsec.d_ptr

            if dt_strtab == None or dt_symtab == None or dt_strent == None:
                return None
            
            break

        self.cached_symtab  = dt_symtab
        self.cached_strtab  = dt_strtab

        if dt_symtab.v() < dt_strtab.v():
            self.cached_numsyms = (dt_strtab.v() - dt_symtab.v()) / dt_strent 
        else:
            self.cached_numsyms = 1024
    
    def _find_symbols(self):
        self._find_symbols_program_headers()

    def symbols(self):
        if self.cached_symtab == None:
            self._find_symbols()
                
        if self.cached_symtab == None:
            return

        rtname = self._get_typename("sym")

        symtab_arr = obj.Object(theType="Array", targetType=rtname, count=self.cached_numsyms, offset = self.cached_symtab, vm = self.obj_vm) 
        for sym in symtab_arr:
            yield sym

    def symbol_at(self, sym_idx):
        ret = None

        for (cur_idx, sym) in enumerate(self.symbols()):
            if cur_idx == sym_idx:
                ret = sym
                break

        return ret            

    def symbol_name(self, sym):
        addr = self.cached_strtab + sym.st_name
        name = self.obj_vm.read(addr, 255)
        if name:
            idx = name.find("\x00")
            if idx != -1:
                name = name[:idx]
        else:
            name = "N/A"
        return name

    def relocation_symbol(self, reloc):
        ridx = reloc.relocation_symbol_index()
        sym = self.symbol_at(ridx)
        return sym

    def relocations(self):
        for phdr in self.program_headers():
            if str(phdr.p_type) != 'PT_DYNAMIC':
                continue
            
            dt_jmprel   = None
            dt_pltrelsz = None
            dt_pltrel   = None

            for dsec in phdr.dynamic_sections():
                if dsec.d_tag == 23:
                    dt_jmprel = dsec.d_ptr

                elif dsec.d_tag == 2:
                    dt_pltrelsz = dsec.d_ptr

                elif dsec.d_tag == 20:
                    dt_pltrel = dsec.d_ptr                  

            if dt_jmprel == None or dt_pltrelsz == None or dt_pltrel == None:
                print "needed info missing"
                return

            if dt_pltrel == 7:
                struct_name = "elf_rela"
                if self.size_cache == 32:
                    struct_size = 12                       
                else:
                    struct_size = 24

            elif dt_pltrel == 17:
                struct_name = "elf_rel"
                if self.size_cache == 32:
                    struct_size = 8          
                else:
                    struct_size = 16
            else:   
                print "unknown relocation type: %d" % dt_pltrel

            # arr = obj.Object(theType="Array", targetType=struct_name, parent = self, count = dt_pltrelsz / struct_size, offset = dt_jmprel, vm = self.obj_vm)


            count = dt_pltrelsz / struct_size
            
            for idx in range(count + 24):
                offset = dt_jmprel + (idx * struct_size)

                reloc = obj.Object(struct_name, offset = offset, vm = self.obj_vm, parent = self)              
                    
                yield reloc 

class elf_shdr(elf):
    """ An elf section header """

    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_shdr", "elf64_shdr", theType, offset, vm, name, **kwargs)    

class elf32_shdr(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_shdr(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_rel(elf):
    """ An elf relocation """

    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_rel", "elf64_rel", theType, offset, vm, name, **kwargs)    

    def relocation_type(self):
        t = self._get_typename("rel")
        if t == "elf32_rel":
            ret = self.r_info & 0xff
        else:
            ret = self.r_info & 0xffffffff

        return ret

    def relocation_symbol_index(self):
        t = self._get_typename("rel")
        if t == "elf32_rel":
            ret = self.r_info >> 8
        else:
            ret = self.r_info >> 32
   
        return ret

class elf32_rel(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_rel(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_rela(elf):
    """ An elf relocation """

    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_rela", "elf64_rela", theType, offset, vm, name, **kwargs)    

    def relocation_type(self):
        t = self._get_typename("rel")
        if t == "elf32_rel":
            ret = self.r_info & 0xff
        else:
            ret = self.r_info & 0xffffffff

        return ret

    def relocation_symbol_index(self):
        t = self._get_typename("rel")
        if t == "elf32_rel":    
            ret = self.r_info >> 8
        else:
            ret = self.r_info >> 32
    
        return ret


class elf32_rela(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_rela(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_phdr(elf):
    """ An elf program header """

    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_phdr", "elf64_phdr", theType, offset, vm, name, **kwargs)    

    def is_valid(self):
        return self.p_filesz > 0 and self.p_memsz > 0

    @property
    def p_vaddr(self):
        ret = self.__getattr__("p_vaddr")

        if self.obj_parent.e_type == 3: # ET_DYN
            ret = self.obj_parent.obj_offset + ret

        return ret

    def dynamic_sections(self):
        # sanity check
        if str(self.p_type) != 'PT_DYNAMIC':
            return

        rtname = self._get_typename("dyn")
        rtsize = self.obj_vm.profile.get_obj_size(rtname)

        tname = "elf_dyn"
        
        # the buffer of array starts at elf_base + our virtual address ( offset )
        arr_start = self.p_vaddr

        for i in range(256):
            # use the real size
            idx = i * rtsize

            dyn = obj.Object(tname, offset = arr_start + idx, vm = self.obj_vm, parent = self)
    
            yield dyn  
            
            if dyn.d_tag == 0:
                break


class elf32_phdr(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_phdr(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_sym(elf):
    """ An elf symbol struct"""
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_sym", "elf64_sym", theType, offset, vm, name, **kwargs)    

class elf32_sym(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_sym(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_dyn(elf):
    """ An elf dynamic section struct"""

    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_dyn", "elf64_dyn", theType, offset, vm, name, **kwargs)    

class elf32_dyn(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_dyn(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_note(elf):
    """An ELF note header"""
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_note", "elf64_note", theType, offset, vm, name, **kwargs)    
 
    def cast_descsz(self, obj_type):
        """Cast the descsz member as a specified type. 
        
        @param obj_type: name of the object 
        
        The descsz member is at a variable offset, which depends
        on the length of the namesz string which precedes it. The
        string is 8-byte aligned and can be zero. 
        """
        
        desc_offset = (self.obj_offset + 
                       self.obj_vm.profile.get_obj_size(self._get_typename("note")) + 
                       ((((self.n_namesz - 1) >> 3) + 1) << 3))
                       
        return obj.Object(obj_type, offset = desc_offset, vm = self.obj_vm, parent = self)    

class elf32_note(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_note(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_link_map(elf):
    """ An libdl link map structure"""
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_link_map", "elf64_link_map", theType, offset, vm, name, **kwargs)    

    @property
    def l_name(self):
        saddr = self.__getattr__("l_name")
        buf = self.obj_vm.zread(saddr, 256)
        idx = buf.find("\x00")
        if idx != -1:
            buf = buf[:idx]
        return str(buf)

    @property
    def l_next(self):
        naddr = self.elf_obj.m("l_next")
        tname = "elf_link_map"
        return obj.Object(tname, offset = naddr, vm = self.obj_vm, parent = self)

    @property
    def l_prev(self):
        naddr = self.elf_obj.m("l_prev")
        tname = "elf_link_map"
        return obj.Object(tname, offset = naddr, vm = self.obj_vm, parent = self)

    def _walk_map_list(self, access_func):
        seen = []
        cur  = self
        while cur:
            if cur.obj_offset in seen:
                break

            yield cur

            seen.append(cur.obj_offset)

            # check for signs of infinite looping
            if len(seen) > 1024:
                break

            cur = access_func(cur)

    def __iter__(self):        
        for member in [lambda x: x.l_next, lambda x: x.l_prev]:
            for mapinfo in self._walk_map_list(member):
                yield mapinfo

class elf32_link_map(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_link_map(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class ELFModification(obj.ProfileModification):
    def modification(self, profile):
        profile.object_classes.update({
                    'elf'      : elf,
                    'elf_hdr'  : elf_hdr, 
                    'elf_note' : elf_note,
                    'elf_phdr' : elf_phdr,
                    'elf32_phdr' : elf32_phdr,
                    'elf64_phdr' : elf64_phdr,
                    'elf_dyn'    : elf_dyn,
                    'elf32_dyn'  : elf32_dyn,
                    'elf64_dyn'  : elf64_dyn,
                    'elf_shdr'   : elf_shdr,
                    'elf32_shdr' : elf32_shdr,
                    'elf64_shdr' : elf64_shdr,
                    'elf_sym'    : elf_sym,
                    'elf32_sym'  : elf32_sym,
                    'elf64_sym'  : elf64_sym,
                    'elf_note'   : elf_note,
                    'elf32_note' : elf32_note,
                    'elf64_note' : elf64_note,
                    'elf_link_map'   : elf_link_map,
                    'elf32_link_map' : elf32_link_map,
                    'elf64_link_map' : elf64_link_map,
                    'elf_rel'    : elf_rel, 
                    'elf32_rel'  : elf32_rel, 
                    'elf64_rel'  : elf64_rel,
                    'elf_rela'   : elf_rela,
                    'elf32_rela' : elf32_rela,
                    'elf64_rela' : elf64_rela 
                     })

class ELF64Modification(obj.ProfileModification):
    def modification(self, profile):
        profile.vtypes.update(elf64_vtypes)

class ELF32Modification(obj.ProfileModification):
    def modification(self, profile):
        profile.vtypes.update(elf32_vtypes)


# Volatility
# Copyright (C) 2007-2011 Volatile Systems
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details. 
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA

# ELF64 format: http://downloads.openwatcom.org/ftp/devel/docs/elf-64-gen.pdf

import volatility.obj as obj


elf32_vtypes = {
    'elf32_hdr' : [ 52, {
        'e_ident' : [ 0, ['String', dict(length = 16)]], 
        'e_type' : [ 16, ['Enumeration', dict(target = 'unsigned short', choices = {
            0: 'ET_NONE', 
            1: 'ET_REL', 
            2: 'ET_EXEC', 
            3: 'ET_DYN', 
            4: 'ET_CORE', 
            0xff00: 'ET_LOPROC', 
            0xffff: 'ET_HIPROC'})]],
        'e_machine' : [ 18, ['unsigned short']], 
        'e_version' : [ 20, ['unsigned int']], 
        'e_entry' : [ 24, ['unsigned int']], 
        'e_phoff' : [ 28, ['unsigned int']], 
        'e_shoff' : [ 32, ['unsigned int']], 
        'e_flags' : [ 36, ['unsigned int']], 
        'e_ehsize'    : [ 40, ['unsigned short']], 
        'e_phentsize' : [ 42, ['unsigned short']], 
        'e_phnum'     : [ 44, ['unsigned short']], 
        'e_shentsize' : [ 46, ['unsigned short']], 
        'e_shnum'     : [ 48, ['unsigned short']], 
        'e_shstrndx'  : [ 50, ['unsigned short']], 
        }], 
 
   'elf32_phdr' : [ 32, {
        'p_type' : [ 0, ['Enumeration', dict(target = 'unsigned int', choices = {
            0: 'PT_NULL', 
            1: 'PT_LOAD',
            2: 'PT_DYNAMIC', 
            3: 'PT_INTERP', 
            4: 'PT_NOTE', 
            5: 'PT_SHLIB', 
            6: 'PT_PHDR', 
            7: 'PT_TLS', 
            0x60000000: 'PT_LOOS', 
            0x6fffffff: 'PT_HIOS', 
            0x70000000: 'PT_LOPROC', 
            0x7fffffff: 'PT_HIPROC'})]],
        'p_offset' : [ 4,  ['unsigned int']], 
        'p_vaddr'  : [ 8,  ['unsigned int']], 
        'p_paddr'  : [ 12, ['unsigned int']], 
        'p_filesz' : [ 16, ['unsigned int']], 
        'p_memsz'  : [ 20, ['unsigned int']], 
        'p_flags'  : [ 24, ['unsigned int']], 
        'p_align'  : [ 28, ['unsigned int']], 
        }], 
    
    'elf32_shdr' : [40, { 
        'sh_name'   : [0,  ['unsigned int']],
        'sh_type'   : [4,  ['unsigned int']],
        'sh_flags'  : [8,  ['unsigned int']],
        'sh_addr'   : [12, ['unsigned int']],
        'sh_offset' : [16, ['unsigned int']],
        'sh_size'   : [20, ['unsigned int']],
        'sh_link'   : [24, ['unsigned int']],
        'sh_info'      : [28, ['unsigned int']],
        'sh_addralign' : [32, ['unsigned int']],
        'sh_entsize'   : [36, ['unsigned int']],
        }],

    'elf32_dyn' : [ 8, {
        'd_tag' : [0, ['int']],
        'd_ptr' : [4, ['unsigned int']],
        }],
 
    'elf32_note' : [ 12, {
        'n_namesz' : [ 0, ['unsigned int']], 
        'n_descsz' : [ 4, ['unsigned int']], 
        'n_type' : [ 8, ['unsigned int']], 
         ## FIXME: this must be cast to int() because the base AS (FileAddressSpace) read method doesn't understand NativeType.
         ## Remove the cast after http://code.google.com/p/volatility/issues/detail?id=350 is fixed. 
        'namesz' : [ 12, ['String', dict(length = lambda x : int(x.n_namesz))]], 
        }],
 
    'elf32_link_map' : [0, {
        'l_addr' : [0, ['unsigned int']], 
        'l_name' : [4, ['unsigned int']], 
        'l_ld'   : [8, ['unsigned int']], 
        'l_next' : [12, ['unsigned int']], 
        'l_prev' : [16, ['unsigned int']], 
        }],

    'elf32_sym' : [ 16, {
        'st_name'   : [ 0,  ['unsigned int']],
        'st_value'  : [ 4,  ['unsigned int']],
        'st_size'   : [ 8,  ['unsigned int']],
        'st_info'   : [ 12, ['unsigned char']],
        'st_other'  : [ 13, ['unsigned char']],
        'st_shndx'  : [ 14,  ['unsigned short']],
    }],

    'elf32_rel' : [ 8, {
        'r_offset' : [ 0,  ['unsigned int']],
        'r_info'   : [ 4,  ['unsigned int']],
    }],

    'elf32_rela' : [ 12, {
        'r_offset' : [ 0,  ['unsigned int']],
        'r_info'   : [ 4,  ['unsigned int']],
        'r_addend' : [ 8,  ['int']],
     }],
}

elf64_vtypes = {
    'elf64_hdr' : [ 64, {
        'e_ident' : [ 0, ['String', dict(length = 16)]], 
        'e_type' : [ 16, ['Enumeration', dict(target = 'unsigned short', choices = {
            0: 'ET_NONE', 
            1: 'ET_REL', 
            2: 'ET_EXEC', 
            3: 'ET_DYN', 
            4: 'ET_CORE', 
            0xff00: 'ET_LOPROC', 
            0xffff: 'ET_HIPROC'})]],
        'e_machine' : [ 18, ['unsigned short']], 
        'e_version' : [ 20, ['unsigned int']], 
        'e_entry' : [ 24, ['unsigned long long']], 
        'e_phoff' : [ 32, ['unsigned long long']], 
        'e_shoff' : [ 40, ['unsigned long long']], 
        'e_flags' : [ 48, ['unsigned int']], 
        'e_ehsize'    : [ 52, ['unsigned short']], 
        'e_phentsize' : [ 54, ['unsigned short']], 
        'e_phnum'     : [ 56, ['unsigned short']], 
        'e_shentsize' : [ 58, ['unsigned short']], 
        'e_shnum'     : [ 60, ['unsigned short']], 
        'e_shstrndx'  : [ 62, ['unsigned short']], 
        }],
 
    'elf64_phdr' : [ 56, {
        'p_type' : [ 0, ['Enumeration', dict(target = 'unsigned int', choices = {
            0: 'PT_NULL', 
            1: 'PT_LOAD',
            2: 'PT_DYNAMIC', 
            3: 'PT_INTERP', 
            4: 'PT_NOTE', 
            5: 'PT_SHLIB', 
            6: 'PT_PHDR', 
            7: 'PT_TLS', 
            0x60000000: 'PT_LOOS', 
            0x6fffffff: 'PT_HIOS', 
            0x70000000: 'PT_LOPROC', 
            0x7fffffff: 'PT_HIPROC'})]],
        'p_flags' : [ 4, ['unsigned int']], 
        'p_offset' : [ 8, ['unsigned long long']], 
        'p_vaddr' : [ 16, ['unsigned long long']], 
        'p_paddr' : [ 24, ['unsigned long long']], 
        'p_filesz' : [ 32, ['unsigned long long']], 
        'p_memsz' : [ 40, ['unsigned long long']], 
        'p_align' : [ 48, ['unsigned long long']], 
        }], 

    'elf64_shdr' : [64, { 
        'sh_name'   : [0,  ['unsigned int']],
        'sh_type'   : [4,  ['unsigned int']],
        'sh_flags'  : [8,  ['unsigned long long']],
        'sh_addr'   : [16, ['unsigned long long']],
        'sh_offset' : [24, ['unsigned long long']],
        'sh_size'   : [32, ['unsigned long long']],
        'sh_link'   : [40, ['unsigned int']],
        'sh_info'      : [44, ['unsigned int']],
        'sh_addralign' : [48, ['unsigned long long']],
        'sh_entsize'   : [56, ['unsigned long long']],
        }],

    'elf64_dyn' : [ 16, {
        'd_tag' : [0, ['long long']],
        'd_ptr' : [8, ['unsigned long long']],
        }],

    'elf64_note' : [ 12, {
        'n_namesz' : [ 0, ['unsigned int']], 
        'n_descsz' : [ 4, ['unsigned int']], 
        'n_type' : [ 8, ['unsigned int']], 
         ## FIXME: this must be cast to int() because the base AS (FileAddressSpace) read method doesn't understand NativeType.
         ## Remove the cast after http://code.google.com/p/volatility/issues/detail?id=350 is fixed. 
        'namesz' : [ 12, ['String', dict(length = lambda x : int(x.n_namesz))]], 
        }],
    
    'elf64_sym' : [ 24 , {
        'st_name'  : [ 0, ['unsigned int']],
        'st_info'  : [ 4, ['unsigned char']],
        'st_other' : [ 5, ['unsigned char']],
        'st_shndx' : [ 6, ['unsigned short']],
        'st_value' : [ 8, ['unsigned long long']],
        'st_size'  : [ 16, ['unsigned long long']],
    }],

    'elf64_link_map' : [0, {
        'l_addr' : [0, ['unsigned long long']], 
        'l_name' : [8, ['unsigned long long']], 
        'l_ld'   : [16, ['unsigned long long']], 
        'l_next' : [24, ['unsigned long long']], 
        'l_prev' : [32, ['unsigned long long']], 
    }],
   
    'elf64_rel' : [ 16, {
        'r_offset' : [ 0,  ['unsigned long long']],
        'r_info'   : [ 8,  ['unsigned long long']],
    }],

    'elf64_rela' : [ 24, {
        'r_offset' : [ 0,  ['unsigned long long']],
        'r_info'   : [ 8,  ['unsigned long long']],
        'r_addend' : [ 16,  ['long long']],
    }],
}

class elf(obj.CType):
    def __init__(self, is_header, name32, name64, theType, offset, vm, name = None, **kwargs):  
        self.name32 = name32
        self.name64 = name64
        self.elf_obj = None

        if is_header:
            self._init_cache(offset, vm)
        else:
            self.size_cache = -39

        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
    
    def is_valid(self):
        return self.size_cache in [32, 64, -39]

    def _init_cache_from_parent(self):
        self.size_cache = self.obj_parent.size_cache
        
        self._make_elf_obj(self.obj_offset, self.obj_vm)

    def _make_elf_obj(self, offset, vm):
        if self.size_cache == 32:
            self.elf_obj = obj.Object(self.name32, offset = offset, vm = vm)
        elif self.size_cache == 64:
            self.elf_obj = obj.Object(self.name64, offset = offset, vm = vm)
        else:
            self.elf_obj = None
        
    def _set_size_cache(self, offset, vm):
        ei_class = obj.Object("unsigned char", offset = offset + 4, vm = vm)
        if ei_class == 1:
            self.size_cache = 32
        elif ei_class == 2:
            self.size_cache = 64
        else:
            self.size_cache = -42

    def _init_cache(self, offset, vm):
        self._set_size_cache(offset, vm)
        self._make_elf_obj(offset, vm) 

    def _get_typename(self, typename):
        if self.size_cache == -39:
            self._init_cache_from_parent()

        if self.size_cache == 32:
            typename = "elf32_" + typename
        else:
            typename = "elf64_" + typename

        return typename

    def __getattr__(self, attr):
        if self.size_cache == -39:
            self._init_cache_from_parent()

        return self.elf_obj.__getattr__(attr)

class elf_hdr(elf):
    """An ELF header"""
    
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        # these are populaed on the first call to symbols()
        self.cached_symtab  = None
        self.cached_strtab  = None
        self.cached_numsyms = 0

        elf.__init__(self, 1, "elf32_hdr", "elf64_hdr", theType, offset, vm, name, **kwargs)    

    def is_valid(self):
        return self.elf_obj != None
        
    def program_headers(self):
        rtname = self._get_typename("phdr")
        rtsize = self.obj_vm.profile.get_obj_size(rtname)

        tname = "elf_phdr"
        
        if self.e_phoff < 0 or self.e_phoff > 1000000:
            return

        # the buffer of headers
        arr_start = self.obj_offset + self.e_phoff

        if self.e_phnum > 128:
            phnum = 128
        else:
            phnum = self.e_phnum

        for i in range(phnum):
            # use the real size
            idx = i * rtsize

            phdr = obj.Object("elf_phdr", offset = arr_start + idx, vm = self.obj_vm, parent = self)
            if phdr.is_valid():
                yield phdr  

    def _section_headers(self):
        rtname = self._get_typename("shdr")
        rtsize = self.obj_vm.profile.get_obj_size(rtname)

        tname = "elf_shdr"
       
        if self.e_shoff < 1:
            arr_start = -1
        else:
            # the buffer of headers
            arr_start = self.obj_offset + self.e_shoff

        return (arr_start, rtsize)

    def section_headers(self):
        (arr_start, rtsize) = self._section_headers()

        if arr_start == -1:
            return

        for i in range(self.e_shnum):
            # use the real size
            idx = i * rtsize

            shdr = obj.Object("elf_shdr", offset = arr_start + idx, vm = self.obj_vm, parent = self)
            if shdr.is_valid():
                yield shdr  

    def _find_symbols_program_headers(self):
        for phdr in self.program_headers():
            if not phdr.is_valid() or str(phdr.p_type) != 'PT_DYNAMIC':
                continue                   
    
            dt_strtab = None
            dt_symtab = None    
            dt_strent = None

            for dsec in phdr.dynamic_sections():
                if dsec.d_tag == 5:
                    dt_strtab = dsec.d_ptr

                elif dsec.d_tag == 6:
                    dt_symtab = dsec.d_ptr

                elif dsec.d_tag == 11:
                    dt_strent = dsec.d_ptr

            if dt_strtab == None or dt_symtab == None or dt_strent == None:
                return None
            
            break

        self.cached_symtab  = dt_symtab
        self.cached_strtab  = dt_strtab

        if dt_symtab.v() < dt_strtab.v():
            self.cached_numsyms = (dt_strtab.v() - dt_symtab.v()) / dt_strent 
        else:
            self.cached_numsyms = 1024
    
    def _find_symbols(self):
        self._find_symbols_program_headers()

    def symbols(self):
        if self.cached_symtab == None:
            self._find_symbols()
                
        if self.cached_symtab == None:
            return

        rtname = self._get_typename("sym")

        symtab_arr = obj.Object(theType="Array", targetType=rtname, count=self.cached_numsyms, offset = self.cached_symtab, vm = self.obj_vm) 
        for sym in symtab_arr:
            yield sym

    def symbol_at(self, sym_idx):
        ret = None

        for (cur_idx, sym) in enumerate(self.symbols()):
            if cur_idx == sym_idx:
                ret = sym
                break

        return ret            

    def symbol_name(self, sym):
        addr = self.cached_strtab + sym.st_name
        name = self.obj_vm.read(addr, 255)
        if name:
            idx = name.find("\x00")
            if idx != -1:
                name = name[:idx]
        else:
            name = "N/A"
        return name

    def relocation_symbol(self, reloc):
        ridx = reloc.relocation_symbol_index()
        sym = self.symbol_at(ridx)
        return sym

    def relocations(self):
        for phdr in self.program_headers():
            if str(phdr.p_type) != 'PT_DYNAMIC':
                continue
            
            dt_jmprel   = None
            dt_pltrelsz = None
            dt_pltrel   = None

            for dsec in phdr.dynamic_sections():
                if dsec.d_tag == 23:
                    dt_jmprel = dsec.d_ptr

                elif dsec.d_tag == 2:
                    dt_pltrelsz = dsec.d_ptr

                elif dsec.d_tag == 20:
                    dt_pltrel = dsec.d_ptr                  

            if dt_jmprel == None or dt_pltrelsz == None or dt_pltrel == None:
                print "needed info missing"
                return

            if dt_pltrel == 7:
                struct_name = "elf_rela"
                if self.size_cache == 32:
                    struct_size = 12                       
                else:
                    struct_size = 24

            elif dt_pltrel == 17:
                struct_name = "elf_rel"
                if self.size_cache == 32:
                    struct_size = 8          
                else:
                    struct_size = 16
            else:   
                print "unknown relocation type: %d" % dt_pltrel

            # arr = obj.Object(theType="Array", targetType=struct_name, parent = self, count = dt_pltrelsz / struct_size, offset = dt_jmprel, vm = self.obj_vm)


            count = dt_pltrelsz / struct_size
            
            for idx in range(count + 24):
                offset = dt_jmprel + (idx * struct_size)

                reloc = obj.Object(struct_name, offset = offset, vm = self.obj_vm, parent = self)              
                    
                yield reloc 

class elf_shdr(elf):
    """ An elf section header """

    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_shdr", "elf64_shdr", theType, offset, vm, name, **kwargs)    

class elf32_shdr(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_shdr(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_rel(elf):
    """ An elf relocation """

    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_rel", "elf64_rel", theType, offset, vm, name, **kwargs)    

    def relocation_type(self):
        t = self._get_typename("rel")
        if t == "elf32_rel":
            ret = self.r_info & 0xff
        else:
            ret = self.r_info & 0xffffffff

        return ret

    def relocation_symbol_index(self):
        t = self._get_typename("rel")
        if t == "elf32_rel":
            ret = self.r_info >> 8
        else:
            ret = self.r_info >> 32
   
        return ret

class elf32_rel(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_rel(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_rela(elf):
    """ An elf relocation """

    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_rela", "elf64_rela", theType, offset, vm, name, **kwargs)    

    def relocation_type(self):
        t = self._get_typename("rel")
        if t == "elf32_rel":
            ret = self.r_info & 0xff
        else:
            ret = self.r_info & 0xffffffff

        return ret

    def relocation_symbol_index(self):
        t = self._get_typename("rel")
        if t == "elf32_rel":    
            ret = self.r_info >> 8
        else:
            ret = self.r_info >> 32
    
        return ret


class elf32_rela(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_rela(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_phdr(elf):
    """ An elf program header """

    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_phdr", "elf64_phdr", theType, offset, vm, name, **kwargs)    

    def is_valid(self):
        return self.p_filesz > 0 and self.p_memsz > 0

    @property
    def p_vaddr(self):
        ret = self.__getattr__("p_vaddr")

        if self.obj_parent.e_type == 3: # ET_DYN
            ret = self.obj_parent.obj_offset + ret

        return ret

    def dynamic_sections(self):
        # sanity check
        if str(self.p_type) != 'PT_DYNAMIC':
            return

        rtname = self._get_typename("dyn")
        rtsize = self.obj_vm.profile.get_obj_size(rtname)

        tname = "elf_dyn"
        
        # the buffer of array starts at elf_base + our virtual address ( offset )
        arr_start = self.p_vaddr

        for i in range(256):
            # use the real size
            idx = i * rtsize

            dyn = obj.Object(tname, offset = arr_start + idx, vm = self.obj_vm, parent = self)
    
            yield dyn  
            
            if dyn.d_tag == 0:
                break


class elf32_phdr(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_phdr(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_sym(elf):
    """ An elf symbol struct"""
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_sym", "elf64_sym", theType, offset, vm, name, **kwargs)    

class elf32_sym(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_sym(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_dyn(elf):
    """ An elf dynamic section struct"""

    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_dyn", "elf64_dyn", theType, offset, vm, name, **kwargs)    

class elf32_dyn(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_dyn(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_note(elf):
    """An ELF note header"""
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_note", "elf64_note", theType, offset, vm, name, **kwargs)    
 
    def cast_descsz(self, obj_type):
        """Cast the descsz member as a specified type. 
        
        @param obj_type: name of the object 
        
        The descsz member is at a variable offset, which depends
        on the length of the namesz string which precedes it. The
        string is 8-byte aligned and can be zero. 
        """
        
        desc_offset = (self.obj_offset + 
                       self.obj_vm.profile.get_obj_size(self._get_typename("note")) + 
                       ((((self.n_namesz - 1) >> 3) + 1) << 3))
                       
        return obj.Object(obj_type, offset = desc_offset, vm = self.obj_vm, parent = self)    

class elf32_note(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_note(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf_link_map(elf):
    """ An libdl link map structure"""
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        elf.__init__(self, 0, "elf32_link_map", "elf64_link_map", theType, offset, vm, name, **kwargs)    

    @property
    def l_name(self):
        saddr = self.__getattr__("l_name")
        buf = self.obj_vm.zread(saddr, 256)
        idx = buf.find("\x00")
        if idx != -1:
            buf = buf[:idx]
        return str(buf)

    @property
    def l_next(self):
        naddr = self.elf_obj.m("l_next")
        tname = "elf_link_map"
        return obj.Object(tname, offset = naddr, vm = self.obj_vm, parent = self)

    @property
    def l_prev(self):
        naddr = self.elf_obj.m("l_prev")
        tname = "elf_link_map"
        return obj.Object(tname, offset = naddr, vm = self.obj_vm, parent = self)

    def _walk_map_list(self, access_func):
        seen = []
        cur  = self
        while cur:
            if cur.obj_offset in seen:
                break

            yield cur

            seen.append(cur.obj_offset)

            # check for signs of infinite looping
            if len(seen) > 1024:
                break

            cur = access_func(cur)

    def __iter__(self):        
        for member in [lambda x: x.l_next, lambda x: x.l_prev]:
            for mapinfo in self._walk_map_list(member):
                yield mapinfo

class elf32_link_map(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class elf64_link_map(obj.CType):
    def __init__(self, theType, offset, vm, name = None, **kwargs):
        obj.CType.__init__(self, theType, offset, vm, name, **kwargs)

class ELFModification(obj.ProfileModification):
    def modification(self, profile):
        profile.object_classes.update({
                    'elf'      : elf,
                    'elf_hdr'  : elf_hdr, 
                    'elf_note' : elf_note,
                    'elf_phdr' : elf_phdr,
                    'elf32_phdr' : elf32_phdr,
                    'elf64_phdr' : elf64_phdr,
                    'elf_dyn'    : elf_dyn,
                    'elf32_dyn'  : elf32_dyn,
                    'elf64_dyn'  : elf64_dyn,
                    'elf_shdr'   : elf_shdr,
                    'elf32_shdr' : elf32_shdr,
                    'elf64_shdr' : elf64_shdr,
                    'elf_sym'    : elf_sym,
                    'elf32_sym'  : elf32_sym,
                    'elf64_sym'  : elf64_sym,
                    'elf_note'   : elf_note,
                    'elf32_note' : elf32_note,
                    'elf64_note' : elf64_note,
                    'elf_link_map'   : elf_link_map,
                    'elf32_link_map' : elf32_link_map,
                    'elf64_link_map' : elf64_link_map,
                    'elf_rel'    : elf_rel, 
                    'elf32_rel'  : elf32_rel, 
                    'elf64_rel'  : elf64_rel,
                    'elf_rela'   : elf_rela,
                    'elf32_rela' : elf32_rela,
                    'elf64_rela' : elf64_rela 
                     })

class ELF64Modification(obj.ProfileModification):
    def modification(self, profile):
        profile.vtypes.update(elf64_vtypes)

class ELF32Modification(obj.ProfileModification):
    def modification(self, profile):
        profile.vtypes.update(elf32_vtypes)


# Volatility # Copyright (C) 2007-2011 Volatile Systems # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # ELF64 format: http://downloads.openwatcom.org/ftp/devel/docs/elf-64-gen.pdf ## FIXME: this must be cast to int() because the base AS (FileAddressSpace) read method doesn't understand NativeType. ## Remove the cast after http://code.google.com/p/volatility/issues/detail?id=350 is fixed. ## FIXME: this must be cast to int() because the base AS (FileAddressSpace) read method doesn't understand NativeType. ## Remove the cast after http://code.google.com/p/volatility/issues/detail?id=350 is fixed. An ELF header # these are populaed on the first call to symbols() # the buffer of headers # use the real size # the buffer of headers # use the real size # arr = obj.Object(theType="Array", targetType=struct_name, parent = self, count = dt_pltrelsz / struct_size, offset = dt_jmprel, vm = self.obj_vm) An elf section header An elf relocation An elf relocation An elf program header # ET_DYN # sanity check # the buffer of array starts at elf_base + our virtual address ( offset ) # use the real size An elf symbol struct An elf dynamic section struct An ELF note header Cast the descsz member as a specified type.                   @param obj_type: name of the object                   The descsz member is at a variable offset, which depends         on the length of the namesz string which precedes it. The         string is 8-byte aligned and can be zero. An libdl link map structure # check for signs of infinite looping