#!/usr/bin/env python

import sys
import struct
import os.path

OFFSET_STATE = 0
OFFSET_STACK = 4

# list_head qui contient next et prev
OFFSET_TASKS = 448

# pointeur sur mm_struct
OFFSET_MM = 456
OFFSET_ACTIVEMM = 460

OFFSET_BINFMT = 464

OFFSET_PID = 492
OFFSET_TPID = 496

# pointeur sur task_struct du parent
OFFSET_REALPARENT = 500
OFFSET_PARENT = 504


# pointeur sur struct cred
OFFSET_REALCRED = 704
OFFSET_CRED = 708

# offset du nom du process (comm) dans la struct task_struct
OFFSET_COMM = 724


# taille de struct_cred quel'on va lire (comprend uid, gid, ...)
SIZE_CRED_STRUCT = 36

# taille estimee de task_struct (on prend surement plus que ce que l'on a besoin, mais pas grave)
SIZE_TASK_STRUCT = 1024

# taille de la structure mm_struct (a la louche)
SIZE_MM_STRUCT = 1024

# taille de la structure vm_area_struct que l'on veut garder
SIZE_VMA_STRUCT = 76



# Hardware-wise, we have a two level page table structure, where the first
# level has 4096 entries, and the second level has 256 entries.  Each entry
# is one 32-bit word.  Most of the bits in the second level entry are used
# by hardware, and there aren't any "accessed" and "dirty" bits.
# 
# Linux on the other hand has a three level page table structure, which can
# be wrapped to fit a two level page table structure easily - using the PGD
# and PTE only.  However, Linux also expects one "PTE" table per page, and
# at least a "dirty" bit.
# 
# Therefore, we tweak the implementation slightly - we tell Linux that we
# have 2048 entries in the first level, each of which is 8 bytes (iow, two
# hardware pointers to the second level.)  The second level contains two
# hardware PTE tables arranged contiguously, followed by Linux versions
# which contain the state information Linux needs.  We, therefore, end up
# with 512 entries in the "PTE" level.
# 
# This leads to the page tables having the following layout:
# 
#    pgd             pte
# |        |
# +--------+ +0
# |        |-----> +------------+ +0
# +- - - - + +4    |  h/w pt 0  |
# |        |-----> +------------+ +1024
# +--------+ +8    |  h/w pt 1  |
# |        |       +------------+ +2048
# +- - - - +       | Linux pt 0 |
# |        |       +------------+ +3072
# +--------+       | Linux pt 1 |
# |        |       +------------+ +4096
# 
# See L_PTE_xxx below for definitions of bits in the "Linux pt", and
# PTE_xxx for definitions of bits appearing in the "h/w pt".
# 
# PMD_xxx definitions refer to bits in the first level page table.
# 
# The "dirty" bit is emulated by only granting hardware write permission
# iff the page is marked "writable" and "dirty" in the Linux PTE.  This
# means that a write to a clean page will cause a permission fault, and
# the Linux MM layer will mark the page dirty via handle_pte_fault().
# For the hardware to notice the permission change, the TLB entry must
# be flushed, and ptep_set_access_flags() does that for us.
# 
# The "accessed" or "young" bit is emulated by a similar method; we only
# allow accesses to the page if the "young" bit is set.  Accesses to the
# page will cause a fault, and handle_pte_fault() will set the young bit
# for us as long as the page is marked present in the corresponding Linux
# PTE entry.  Again, ptep_set_access_flags() will ensure that the TLB is
# up to date.
# 
# However, when the "young" bit is cleared, we deny access to the page
# by clearing the hardware PTE.  Currently Linux does not flush the TLB
# for us in this case, which means the TLB will retain the transation
# until either the TLB entry is evicted under pressure, or a context
# switch which changes the user space mapping occurs.


PTRS_PER_PTE = 512
PTRS_PER_PMD = 1
PTRS_PER_PGD = 2048


# PMD_SHIFT determines the size of the area a second-level page table can map
# PGDIR_SHIFT determines what a third-level page table entry can map


#PMD_SHIFT = 22
#PGDIR_SHIFT = 22
PMD_SHIFT = 21
PGDIR_SHIFT = 21
PAGE_SHIFT = 12

def hex_print(data):
    s = ""
    l = len(data)
    m = l%4
    if m != 0:
        data += '\x00'*(m)
        print "on a ajoute %d 0 a la fin pour s'aligner sur 4 octets"%(m)
        l += m
    for i in range(0, l, 4):
        d = struct.unpack("<L", data[i:i+4])[0]
        if d != 0:
            s += "0x%08x (-%d) "%(d,l-i)  
    print s


# thanks volatility
def page_size_flag(entry):
    if (entry & (1 << 7)) == (1 << 7):
        return True
    return False   

def entry_present(entry):
    if (entry & (0x00000001)) == 0x00000001:
        return True
    return False


def pgd_index( pgd):
    return (pgd >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)

def get_pgd(pgd_vaddr, vaddr, all_data):     
    pgd_entry = pgd_vaddr + pgd_index(vaddr) * 8  # (pointer size * 2)
    #print "in get_pgd : pgd_vaddr : 0x%08x , vaddr : 0X%08x, len(all_data) : %d, pgd_entry : 0x%08x "%(pgd_vaddr, vaddr, len(all_data), pgd_entry)
    pgd_entry -= 0xC0000000
    val = struct.unpack("<L", all_data[pgd_entry:pgd_entry+4])[0]
    #print "tjs dans get_pgd, pgd_entry vaut maintenant : 0x%08x et on a lu 0x%08x"%(pgd_entry, val)
    return val

def pte_pfn(pte):
    return pte >> PAGE_SHIFT

def pte_index(pte):
    val = (pte >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)
    #print "in pte_index, index : 0x%08x (donc index reel (*4) : 0x%08x )"%(val, val*4)
    return val

def get_pte(vaddr, pgd, all_data):
    #print "in get_pte : vaddr : 0x%08x , pgd : 0x%08x"%(vaddr, pgd)
    pgd_val = pgd & ~((1 << PAGE_SHIFT) - 1)
    #print "in get_pte : pgd_val : 0x%08x"%pgd_val
    pgd_val = pgd_val + pte_index(vaddr) * 4 # (pointer size)
    #print "in get_pte : pgd_val : 0x%08x"%pgd_val
    return struct.unpack("<L", all_data[pgd_val:pgd_val+4])[0]

def get_paddr(vaddr, pte):
    val = (pte_pfn(pte) << PAGE_SHIFT) | (vaddr & ((1 << PAGE_SHIFT) - 1))
    #print "in get_paddr : vaddr : 0x%08x , pte : 0x%08x , val retournee : 0x%08x"%(vaddr, pte, val)
    return val

def get_four_meg_paddr(vaddr, pgd_entry):
    return (pgd_entry & ((PTRS_PER_PGD-1) << PGDIR_SHIFT)) | (vaddr & ~((PTRS_PER_PGD-1) << PGDIR_SHIFT))

# conversion adresse virtuelle vers physique
# on doit donner all_data pour pouvoir acceder a pmd et pte depuis pgd
def virt2phy(vaddr, mmpgd=None, all_data=None):
    # conversion pour adresse noyau, on enleve simplement 0xC0000000
    if mmpgd == None and all_data==None and vaddr >= 0xC0000000:
        return vaddr - 0xC0000000
    else:
        #print "in virt2phy : vaddr : 0x%08x , mmpgd : 0x%08x"%(vaddr, mmpgd)
        pgd = get_pgd(mmpgd, vaddr, all_data)
        #print "pgd = 0x%08x"%(pgd)
        if entry_present(pgd):
            if page_size_flag(pgd):
                return get_four_meg_paddr(vaddr, pgd)
            else:      
                pte = get_pte(vaddr, pgd, all_data)
                #print "pte : 0x%08x"%pte
                if not pte : return None
                #if entry_present(pte):
                return get_paddr(vaddr, pte)
        else:
            return None


class ListHead:
    def __init__(self, name, value):
        self.name = name       
        self.next = struct.unpack("<L",value[:4])[0]
        self.prev = struct.unpack("<L",value[4:])[0]

    def __str__(self):
        return "%s :  next -> 0x%08X , prev -> 0x%08X"%(self.name, self.next, self.prev)


class Cred:
    def __init__(self, data):
        self.usage = struct.unpack("<L", data[0:4])[0]
        self.uid = struct.unpack("<L", data[4:8])[0]
        self.gid = struct.unpack("<L", data[8:12])[0]
        self.suid = struct.unpack("<L", data[12:16])[0]
        self.sgid = struct.unpack("<L", data[16:20])[0]
        self.euid = struct.unpack("<L", data[20:24])[0]
        self.egid = struct.unpack("<L", data[24:28])[0]
        self.fsuid = struct.unpack("<L", data[28:32])[0]
        self.fsgid = struct.unpack("<L", data[32:36])[0]

    def __str__(self):
        return "usage : %d , uid : %d , gid : %d"%(self.usage, self.uid, self.gid)

class VMArea:
    def __init__(self, data, all_data):
        #	struct mm_struct * vm_mm;	/* The address space we belong to. */
        #	unsigned long vm_start;		/* Our start address within vm_mm. */
        #	unsigned long vm_end;		/* The first byte after our end address within vm_mm. */

        #	/* linked list of VM areas per task, sorted by address */
	    #   struct vm_area_struct *vm_next;

        self.vm_mm = struct.unpack("<L", data[0:4])[0]
        self.vm_start = struct.unpack("<L", data[4:8])[0]
        self.vm_end = struct.unpack("<L", data[8:12])[0]
        self.vm_next = struct.unpack("<L", data[12:16])[0]
        self.vm_page_prot = struct.unpack("<L", data[16:20])[0]
        self.vm_flags = struct.unpack("<L", data[20:24])[0]

        # offset dans file quand vm pointe sur un fichier (fichier mmappe)
        # l'unite est la PAGE_SIZE (4096 octets) donc si == 1 , offset est de 4096 octets
        #	  unsigned long vm_pgoff;		/* Offset (within vm_file) in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */
        #	  struct file * vm_file;		/* File we map to (can be NULL). *
        self.vm_pgoff = struct.unpack("<L", data[68:72])[0]
        self.vm_file = struct.unpack("<L", data[72:76])[0]
        
        # fichier associe au vma
        if self.vm_file != 0:
            self.filename = self._get_file_full_path(self.vm_file, all_data)
        else:
            self.filename = ""

    # au lieu d'afficher 5 par exemple, on affiche r-x
    def _readable_flags(self, flags):
        VM_READ		= 0x00000001
        VM_WRITE	= 0x00000002
        VM_EXEC		= 0x00000004
        VM_SHARED	= 0x00000008
        s = ""
        if flags & VM_READ:
            s = "r"
        else:
            s = "-"
        if flags & VM_WRITE:
            s += "w"
        else:
            s += "-"
        if flags & VM_EXEC:
            s += "x"
        else:
            s += "-"
        # shared ou private
        if flags & VM_SHARED:
            s += "s"
        else:
            s += "p" 
        return s                

    def __str__(self):
        # 00008000-00009000 r-xp 00000000   /system/bin/app_process
        flags = self._readable_flags(self.vm_flags)
        return "%08x-%08x %s %08x   %s"%(self.vm_start, self.vm_end, flags, self.vm_pgoff*4096, self.filename)

    # on prend en parametre l'adresse virtuelle de la dentry, all_data est l'ensemble de l'image lue en memoire
    def _read_filename_from_dentry(self, dentry_vaddr, all_data):
        addr = virt2phy(dentry_vaddr)
        # len_fichier est a l'offset 32 dans la dentry, et le ptr sur le nom de fichier est a l'offset 36
        len_fichier = struct.unpack("<L", all_data[addr+32:addr+36])[0]
        vaddr_fichier = struct.unpack("<L", all_data[addr+36:addr+40])[0]
        addr_fichier = virt2phy(vaddr_fichier)
      #  print "addr : 0x%08x, len_fichier : %d , addr_fichier : 0x%08x"%(addr, len_fichier, addr_fichier)
        fichier_name = all_data[addr_fichier:addr_fichier+len_fichier]
        #print "_read_filename_from_dentry : len_fichier : %d , addr_fichier : 0x%08x"%(len_fichier, addr_fichier)
        return fichier_name

    # retourne l'addresse de la dentry contenue dans path
    def _get_dentry_from_struct_file(self, file_vaddr, all_data):
        #print "_get_dentry_from_struct_file, file_vaddr : 0x%08x"%file_vaddr
        addr = virt2phy(file_vaddr)
        dentry_addr = struct.unpack("<L", all_data[addr+12:addr+16])[0]
        return dentry_addr

    # retourne l'addresse du vfsmount contenu dans path
    def _get_vfsmount_from_struct_file(self, file_vaddr, all_data):
        addr = virt2phy(file_vaddr)
        vfs_addr = struct.unpack("<L", all_data[addr+8:addr+12])[0]
        return vfs_addr

    def _get_file_directory_path(self, file_vaddr, all_data):
        # on recupere d'abord l'adresse du vfsmount
        self._get_vfsmount_from_struct_file(file_vaddr, all_data)

    def _get_vfsmount_full_path(self, vfsmount_vaddr, all_data):
        s = ""
        addr = virt2phy(vfsmount_vaddr)
        mnt_parent = struct.unpack("<L", all_data[addr+8:addr+12])[0]
        # on est pas root, on appelle recursivement la fonction pour obtenir les paths de ceux du dessus
        if mnt_parent != vfsmount_vaddr:
            s = self._get_vfsmount_full_path(mnt_parent, all_data)
        # en arrivant la, on est soit root, soit on a traite ceux du dessus
        # on recupere la dentry associe
        dentry_vaddr = struct.unpack("<L", all_data[addr+12:addr+16])[0]
        s += self._read_filename_from_dentry(dentry_vaddr, all_data)
        return s

    def _get_file_full_path(self, file_vaddr, all_data):
        # prend la dentry contenue dans le file *
        dentry = self._get_dentry_from_struct_file(file_vaddr, all_data)
        dentry_name = self._read_filename_from_dentry(dentry, all_data)
        vfs = self._get_vfsmount_from_struct_file(self.vm_file, all_data)
        vfs_name = self._get_vfsmount_full_path(vfs, all_data)
        
        return os.path.join(vfs_name, dentry_name)

# Passer d'un file * au nom du fichier derriere
# le nom est dans struct qstr d_name;  
#
#struct file {
#	/*
#	 * fu_list becomes invalid after file_free is called and queued via
#	 * fu_rcuhead for RCU freeing
#	 */
#	union {
#		struct list_head	fu_list;
#		struct rcu_head 	fu_rcuhead;
#	} f_u;
#	struct path		f_path; 
#	const struct file_operations	*f_op;
#	atomic_long_t		f_count;
#
#
#
#struct path {
#	struct vfsmount *mnt;
#	struct dentry *dentry;  <== OFFSET 12 dans le struct file
#};
#
#
#struct dentry {
#	atomic_t d_count;
#	unsigned int d_flags;		/* protected by d_lock */
#	spinlock_t d_lock;		/* per dentry lock */
#	int d_mounted;
#	struct inode *d_inode;		/* Where the name belongs to - NULL is negative */
#	/*
#	 * The next three fields are touched by __d_lookup.  Place them here
#	 * so they all fit in a cache line.
#	 */
#	struct hlist_node d_hash;	/* lookup hash list */
#	struct dentry *d_parent;	/* parent directory */
#	struct qstr d_name;  <== XXX
#
#
# struct qstr {
#	unsigned int hash;
#	unsigned int len;   <=== OFFSET 32 dans struct dentry
#	const unsigned char *name; <=== OFFSET 36
#};

# struct vfsmount {
#	struct list_head mnt_hash;
#	struct vfsmount *mnt_parent;	/* fs we are mounted on */
#	struct dentry *mnt_mountpoint;	/* dentry of mountpoint */
#	struct dentry *mnt_root;	/* root of the mounted tree */
#	struct super_block *mnt_sb;	/* pointer to superblock */
#
# algo pour aller chercher le chemin du repertoire du fichier :
# dans le vfsmount de path du file *, regarder si mnt_parent pointe sur nous meme (i.e le vfsmount mnt, dans ce cas on a plus de parent), dans ce cas, aller chercher le path dans le dentry "mnt_mountpoint"


class MM:
    def __init__(self, data, all_data):
        # struct vm_area_struct * mmap;		/* list of VMAs */
        self.mmap = struct.unpack("<L", data[0:4])[0]
        # on s'en moque :
	    #    struct rb_root mm_rb;
	    #    struct vm_area_struct * mmap_cache;	/* last find_vma result */
	    #    unsigned long (*get_unmapped_area) (struct file *filp,
	    #			unsigned long addr, unsigned long len,
	    #			unsigned long pgoff, unsigned long flags);
	    #    void (*unmap_area) (struct mm_struct *mm, unsigned long addr);

	    # unsigned long mmap_base;		/* base of mmap area */
        self.mmap_base = struct.unpack("<L", data[20:24])[0]
	    # unsigned long task_size;		/* size of task vm space */
        self.task_size = struct.unpack("<L", data[24:28])[0]

    	# pgd_t * pgd;
        self.pgd = struct.unpack("<L", data[36:40])[0]
        #	atomic_t mm_users;			/* How many users with user space? */
        #	atomic_t mm_count;			/* How many references to "struct mm_struct" (users count as 1) */
        #	int map_count;				/* number of VMAs */
        self.map_count = struct.unpack("<L", data[48:52])[0]
        # compte pour 12 octets ici seulement
        # struct rw_semaphore mmap_sem;
        # spinlock_t page_table_lock;		/* Protects page tables and some counters */
        self.mmlist = ListHead("mmlist", data[64:72])

        #	mm_counter_t _file_rss;
        #	mm_counter_t _anon_rss;

        #	unsigned long hiwater_rss;	/* High-watermark of RSS usage */
        #	unsigned long hiwater_vm;	/* High-water virtual memory usage */
        self.hiwater_rss = struct.unpack("<L", data[80:84])[0]
        self.hiwater_vm = struct.unpack("<L", data[84:88])[0]
        #	unsigned long total_vm, locked_vm, shared_vm, exec_vm;
        self.total_vm = struct.unpack("<L", data[88:92])[0]
        self.locked_vm =  struct.unpack("<L", data[92:96])[0]
        self.shared_vm = struct.unpack("<L", data[96:100])[0]
        self.exec_vm = struct.unpack("<L", data[100:104])[0]
        #	unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;
        self.stack_vm = struct.unpack("<L", data[104:108])[0]
        self.reserved_vm = struct.unpack("<L", data[108:112])[0]
        self.def_flags = struct.unpack("<L", data[112:116])[0]
        self.nr_ptes = struct.unpack("<L", data[116:120])[0]
        #	unsigned long start_code, end_code, start_data, end_data;
        self.start_code = struct.unpack("<L", data[120:124])[0]
        self.end_code = struct.unpack("<L", data[124:128])[0]
        self.start_data = struct.unpack("<L", data[128:132])[0]
        self.end_date = struct.unpack("<L", data[132:136])[0]
        #	unsigned long start_brk, brk, start_stack;
        self.start_brk = struct.unpack("<L", data[136:140])[0]
        self.brk = struct.unpack("<L", data[140:144])[0]
        self.start_stack = struct.unpack("<L", data[144:148])[0]
        #	unsigned long arg_start, arg_end, env_start, env_end;
        self.arg_start = struct.unpack("<L", data[148:152])[0]
        self.arg_end = struct.unpack("<L", data[152:156])[0]
        self.env_start = struct.unpack("<L", data[156:160])[0]
        self.env_end = struct.unpack("<L", data[160:164])[0]


        self.vma_list = []
        # on va parcourir tous les VMA de mmap
        vma = VMArea(all_data[virt2phy(self.mmap):virt2phy(self.mmap) + SIZE_VMA_STRUCT], all_data)
        self.vma_list.append(vma)
        while vma.vm_next != 0:
            next_addr = virt2phy(vma.vm_next)
            vma = VMArea(all_data[next_addr:next_addr + SIZE_VMA_STRUCT], all_data)
            # heap
            if vma.vm_start == self.start_brk:
                vma.filename = "[heap]"
            # stack
            if vma.vm_start <= self.start_stack and vma.vm_end >= self.start_stack:
                vma.filename = "[stack]"   
            self.vma_list.append(vma)

       
    def vma_list2str(self):     
        s = ""
        for z in range(len(self.vma_zone)):
            start, end, cpt = self.vma_zone[z]
            s += "Zone %d : start : 0x%08x , end :  0x%08x (size : 0x%x) , vma dans zone : %d\n"%(z, start, end, end-start, cpt)
        return s
        
    def __str__(self):
        s = ""
        ##############
        # XXX : commenter les 2 lignes suivantes pour ne pas afficher tous les VMA de chaque process
        ############## 
        for v in self.vma_list:
            s += "%s\n"%str(v)
        return "mmap : 0x%08x  , mmap_base : 0x%08x , task_size : 0x%08x , pgd : 0x%08x , map_count : %d\n\n%s"%(self.mmap, self.mmap_base, self.task_size, self.pgd, self.map_count, s)

class TaskStruct:
    def __init__(self, data, all_data):
        self.state = struct.unpack("<L", data[OFFSET_STATE:OFFSET_STATE+4])[0]
        self.stack = struct.unpack("<L", data[OFFSET_STACK:OFFSET_STACK+4])[0]
        self.tasks = ListHead("tasks",data[OFFSET_TASKS:OFFSET_TASKS+8])
        self.next = self.tasks.next
        self.prev = self.tasks.prev
        self.mm_addr = struct.unpack("<L", data[OFFSET_MM:OFFSET_MM+4])[0]
        if self.mm_addr > 0:
            self.mm_addr -= 0xC0000000
            self.mm = MM(all_data[self.mm_addr : self.mm_addr+SIZE_MM_STRUCT], all_data)
        else:
            self.mm = None
        self.activemm = struct.unpack("<L", data[OFFSET_ACTIVEMM:OFFSET_ACTIVEMM+4])[0]
        self.binfmt = struct.unpack("<L", data[OFFSET_BINFMT:OFFSET_BINFMT+4])[0]
        self.pid = struct.unpack("<L", data[OFFSET_PID:OFFSET_PID+4])[0]
        self.tpid = struct.unpack("<L", data[OFFSET_TPID:OFFSET_TPID+4])[0]
        self.realparent = struct.unpack("<L", data[OFFSET_REALPARENT:OFFSET_REALPARENT+4])[0]
        self.parent = struct.unpack("<L", data[OFFSET_PARENT:OFFSET_PARENT+4])[0]
        # pointeur vers struct cred
        self.realcred_addr = struct.unpack("<L", data[OFFSET_REALCRED:OFFSET_REALCRED+4])[0]
        # adresse virtuelle vers physique pour le noyau -> (addr - 0xc00000)
        self.realcred_addr -= 0xc0000000
        self.realcred = Cred(all_data[self.realcred_addr:self.realcred_addr+SIZE_CRED_STRUCT])
        self.usage = self.realcred.usage
        self.uid = self.realcred.uid
        self.gid = self.realcred.gid
        # pointeur vers struct cred
        self.cred_addr = struct.unpack("<L", data[OFFSET_CRED:OFFSET_CRED+4])[0]
        # adresse virtuelle vers physique pour le noyau -> (addr - 0xc00000)
        self.cred_addr -= 0xc00000
        # le champs comm fait 16 octets max
        self.name = data[OFFSET_COMM:OFFSET_COMM+16]

    def __str__(self):
      #  if self.mm == None:
      #      vma_list = ""
      #  else:
      #      vma_list = self.mm.vma_list2str()
        return "====== %s ======= \n \
                PID : %d \n \
                UID : %d , GID : %d \n \
                next : 0x%08x , prev : 0x%08x \n \
                parent : 0x%08x \n \
                mm_addr : 0x%08x \n \
                state : %d \n \
                stack : 0x%08x \n \
                %s "%(
                self.name,
                self.pid,
                self.uid, 
                self.gid,
                self.next,
                self.prev,
                self.parent,
                self.mm_addr+0xC0000000,
                self.state,
                self.stack,
                self.mm)

class SymbolTable:
    # chaque ligne de la forme "c0748e80 D init_task"
    def __init__(self, fd):
        self.symbols = {}
        data = fd.read().split('\n')
        for line in data:
            line = line.strip()
            if line:
                address, the_type, name = line.split(' ')
                self.symbols[name] = int(address,16)

    def get_symbol(self, symbol):
        if self.symbols.has_key(symbol):
            return self.symbols[symbol]
        else:
            return None
        



if len(sys.argv) != 3:
    print "Usage : %s fichier_memoire system.map"%sys.argv[0]
    sys.exit(-1)


sym_file = open(sys.argv[2], "r")
sym_tab = SymbolTable(sym_file)
sym_file.close()

for i in ['init_task', 'swapper_pg_dir']:
    print "%s : 0x%0x"%(i, sym_tab.get_symbol(i))

mem_file = open(sys.argv[1], "r")
# ouch!!! on lit tout le fichier en RAM...
data = mem_file.read()
mem_file.close()


init_task_addr = sym_tab.get_symbol('init_task')
# passage virtual -> physique
#init_task_addr -= 0xC0000000
init_task_addr = virt2phy(init_task_addr)
print "init_task_addr (swapper): 0x%08x"%init_task_addr
task = TaskStruct(data[init_task_addr : init_task_addr+SIZE_TASK_STRUCT], data)
print task

task_list = {}
task_list[task.pid] = task
next_task_addr  = task.next - 0xC0000000
# next_task_addr pointe sur next de tasks de la task_struct, on le fait pointer maintenant sur le debut de la structure
next_task_addr -= OFFSET_TASKS

loop = 1
while loop == 1:
    task = TaskStruct(data[next_task_addr : next_task_addr+SIZE_TASK_STRUCT], data)
    # on a boucle sur la liste des pid
    if task.pid in task_list.keys():
        loop = 0
    # on continue
    else:
        print task
        task_list[task.pid] = task
        next_task_addr  = task.next - 0xC0000000
        # next_task_addr pointe sur next de tasks de la task_struct, on le fait pointer maintenant sur le debut de la structure
        next_task_addr -= OFFSET_TASKS


sys.exit(0)
####################
#
# Cette partie sert à dumper le contenu des pages memoire dans un fichier (pour recuperer les apk par exemple)
# decommenter le sys.exit du dessus et modifier les valeurs 
# de toute maniere, le code est tres sale...
#
####################
PID = 233

if PID in task_list.keys():
#for pid in task_list.keys():
    pid = PID
    print "PID : %d"%pid
    #task = task_list[pid]
    task = task_list[PID]
    if task.mm != None:
        pgd = task.mm.pgd
        fd = open("/tmp/test-%d"%pid,"w")
        print "pgd du pid %d : 0x%08x"%(PID, pgd)
        vma_list = task.mm.vma_list
      #  for i in range(0x426f3000, 0x42701000, 4096):
     #   for i in range(0xbeb7e000, 0xbeb93000, 4096):
        for i in range(0x426f3000, 0x426f9000, 4096):
            aa = virt2phy(i, pgd, data)
	    if aa == None:
	        print "adresse 0x%08x non resolue"%i
            else:
	        print "0x%08x ==> 0x%08x"%(i, aa)
                page_data = data[aa:aa+4096]
                fd.write(page_data)
#        for vm_area in vma_list:
#            for i in range(vm_area.vm_start, vm_area.vm_end, 4096):
#                aa = virt2phy(i, pgd, data)
#                if aa == None:
#                    print "adresse 0x%08x non resolue"%i
#                else:
#                    print "0x%08x ==> 0x%08x"%(i, aa)
#                    page_data = data[aa:aa+4096]
#                    fd.write(page_data)
        fd.close()
        

