diff --git a/linux-ramdump-parser-v2/.gitignore b/linux-ramdump-parser-v2/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..6a07bffaedfd668ad17fe71a3c5650377b7d9881
--- /dev/null
+++ b/linux-ramdump-parser-v2/.gitignore
@@ -0,0 +1 @@
+local_settings.py
diff --git a/linux-ramdump-parser-v2/README b/linux-ramdump-parser-v2/README
new file mode 100644
index 0000000000000000000000000000000000000000..6819a253f1bde68afaaedf74889e55430e345b82
--- /dev/null
+++ b/linux-ramdump-parser-v2/README
@@ -0,0 +1,72 @@
+Python Linux Ramdump Parser
+
+What does this tool do?
+----------------------------------
+This tool takes as its input a vmlinux symbol file, and files representing
+memory from devices that run Linux. It proceeds to dump useful information
+such as process stacks, IRQ and workqueue information.
+
+What does this tool need?
+----------------------------------
+1) Python. This tool has been tested with Python 2.6.5 on both Linux and Windows
+1) a set of RAM dumps. Ideally, the load location of each dump as well.
+2) The corresponding vmlinux file
+
+How is this tool invoked?
+----------------------------------
+python ramparse.py invokes the parser. Options:
+
+--ram-file <file path> <start> <end> : Add this ram file to be parsed.
+At least one of --ram-file and --auto-dump required
+
+--vmlinux <path> : path for vmlinux to use. This is required
+
+--auto-dump <path to folder> : Automatically find files for a RAM dump and
+detect useful informaton.
+
+--gdb-path <path> : path for the GNU gdb debugger. If no path is given, the
+path will be used from local_settings.py
+
+--gdb-path <path> : path for the nm tool. If no path is given, the
+path will be used from local_settings.py
+
+--outdir <path> : Output directory to store any files written. If no path is
+given, the ramfile directory will be used if given, else the current directory
+will be used.
+
+--out-file <path> : File to write all output to. If no path is given,
+linux-parser-output.txt is used
+
+--stdout : Write to stdout instead of the out-file. This overrides any
+--out-file given.
+
+The list of features parsed is constantly growing. Please use --help option
+to see the full list of features that can be parsed.
+
+Setting up the toolchains
+-------------------------------
+The parser relies on having access to gdb and nm to work. You will need to
+specify the paths to these tools. This can be done in three ways
+
+1) Using --gdb-path and --nm-path to specify the absolute path
+2) Using CROSS_COMPILE to specify the prefix
+3) Using local_settings.py as described below
+
+Just having gdb/nm on the path is not supported as there are too many
+variations on names to invoke.
+
+local_settings.py
+-------------------------------
+The parser attempts to figure out most of the settings automatically but there
+are some settings that are unique to the environment of the running system.
+These must be specified in local_settings.py. The current format for the file
+is
+
+<setting name> = <string identifying the feaure>
+
+Currently supported features:
+gdb_path - absolute path to the gdb tool for the ramdumps
+nm_path - absolute path to the gdb tool for the ramdumps
+
+Note that local_settings.py is just a python file so the file may take advantage
+of python features.
diff --git a/linux-ramdump-parser-v2/bitops.py b/linux-ramdump-parser-v2/bitops.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc2d3108425cb1f5ee225f53bed8a7b66d700776
--- /dev/null
+++ b/linux-ramdump-parser-v2/bitops.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+
+def bm(msb, lsb):
+    'Creates a bitmask from msb to lsb'
+    return int(('1' * (msb - lsb + 1)) + ('0' * lsb), 2)
+
+
+def bvalsel(msb, lsb, val):
+    'Masks and returns the bits from msb to lsb in val'
+    return ((val & bm(msb, lsb)) >> lsb)
diff --git a/linux-ramdump-parser-v2/gdbmi.py b/linux-ramdump-parser-v2/gdbmi.py
new file mode 100644
index 0000000000000000000000000000000000000000..cdccdd078ea4d0622ca0d35d659522dc7158874a
--- /dev/null
+++ b/linux-ramdump-parser-v2/gdbmi.py
@@ -0,0 +1,231 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import sys
+import re
+import subprocess
+
+GDB_SENTINEL = '(gdb) '
+GDB_DATA_LINE = '~'
+GDB_OOB_LINE = '^'
+
+
+def gdb_hex_to_dec(val):
+    match = re.search('(0x[0-9a-fA-F]+)', val)
+    return int(match.group(1), 16)
+
+
+class GdbSymbol(object):
+
+    def __init__(self, symbol, section, addr):
+        self.symbol = symbol
+        self.section = section
+        self.addr = addr
+
+
+class GdbMIResult(object):
+
+    def __init__(self, lines, oob_lines):
+        self.lines = lines
+        self.oob_lines = oob_lines
+
+
+class GdbMIException(Exception):
+
+    def __init__(self, *args):
+        self.value = '\n *** '.join([str(i) for i in args])
+
+    def __str__(self):
+        return self.value
+
+
+class GdbMI(object):
+
+    def __init__(self, gdb_path, elf):
+        self.gdb_path = gdb_path
+        self.elf = elf
+        self._cache = {}
+        self._gdbmi = None
+
+    def open(self):
+        self._gdbmi = subprocess.Popen(
+            [self.gdb_path, '--interpreter=mi2', self.elf],
+            stdin=subprocess.PIPE,
+            stdout=subprocess.PIPE
+        )
+        self._flush_gdbmi()
+
+    def close(self):
+        self._gdbmi.communicate('quit')
+
+    def __enter__(self):
+        self.open()
+        return self
+
+    def __exit__(self, ex_type, ex_value, ex_traceback):
+        self.close()
+
+    def _flush_gdbmi(self):
+        while True:
+            line = self._gdbmi.stdout.readline().rstrip('\r\n')
+            if line == GDB_SENTINEL:
+                break
+
+    def _run(self, cmd, skip_cache=False, save_in_cache=True):
+        """Runs a gdb command and returns a GdbMIResult of the result. Results
+        are cached (unless skip_cache=True) for quick future lookups.
+
+        - cmd: Command to run (e.g. "show version")
+        - skip_cache: Don't use a previously cached result
+        - save_in_cache: Whether we should save this result in the cache
+
+        """
+        if self._gdbmi is None:
+            raise Exception(
+                'BUG: GdbMI not initialized. ' +
+                'Please use GdbMI.open or a context manager.')
+
+        if not skip_cache:
+            if cmd in self._cache:
+                return GdbMIResult(self._cache[cmd], [])
+
+        self._gdbmi.stdin.write(cmd.rstrip('\n') + '\n')
+        self._gdbmi.stdin.flush()
+
+        output = []
+        oob_output = []
+        while True:
+            line = self._gdbmi.stdout.readline().rstrip('\r\n')
+            if line == GDB_SENTINEL:
+                break
+            if line.startswith(GDB_DATA_LINE):
+                # strip the leading "~"
+                line = line[1:]
+                # strip the leading and trailing "
+                line = line[1:-1]
+                # strip any trailing (possibly escaped) newlines
+                if line.endswith('\\n'):
+                    line = line[:-2]
+                elif line.endswith('\n'):
+                    line = line.rstrip('\n')
+                output.append(line)
+            if line.startswith(GDB_OOB_LINE):
+                oob_output.append(line[1:])
+
+        if save_in_cache:
+            self._cache[cmd] = output
+
+        return GdbMIResult(output, oob_output)
+
+    def _run_for_one(self, cmd):
+        result = self._run(cmd)
+        if len(result.lines) != 1:
+            raise GdbMIException(
+                cmd, '\n'.join(result.lines + result.oob_lines))
+        return result.lines[0]
+
+    def _run_for_first(self, cmd):
+        return self._run(cmd).lines[0]
+
+    def version(self):
+        """Return GDB version"""
+        return self._run_for_first('show version')
+
+    def field_offset(self, the_type, field):
+        """Returns the offset of a field in a struct or type.
+
+        Example:
+
+        gdbmi.field_offset("struct ion_buffer", "heap")
+        -> 20
+
+        - `the_type': struct or type (note that if it's a struct you
+          should include the word "struct" (e.g.: "struct
+          ion_buffer"))
+
+        - `field': the field whose offset we want to return
+
+        """
+        cmd = 'print /x (int)&(({0} *)0)->{1}'.format(the_type, field)
+        result = self._run_for_one(cmd)
+        return gdb_hex_to_dec(result)
+
+    def sizeof(self, the_type):
+        """Returns the size of the type specified by `the_type'."""
+        result = self._run_for_one('print /x sizeof({0})'.format(the_type))
+        return gdb_hex_to_dec(result)
+
+    def address_of(self, symbol):
+        """Returns the address of the specified symbol."""
+        result = self._run_for_one('print /x &{0}'.format(symbol))
+        return int(result.split(' ')[-1], 16)
+
+    def get_symbol_info(self, address):
+        """Returns a GdbSymbol representing the nearest symbol found at
+        `address'."""
+        result = self._run_for_one('info symbol ' + hex(address))
+        parts = result.split(' ')
+        if len(parts) < 2:
+            raise GdbMIException('Output looks bogus...', result)
+        symbol = parts[0]
+        section = parts[-1]
+        return GdbSymbol(symbol, section, address)
+
+    def symbol_at(self, address):
+        """Get the symbol at the specified address (using `get_symbol_info')"""
+        return self.get_symbol_info(address).symbol
+
+    def get_enum_lookup_table(self, enum, upperbound):
+        """Return a table translating enum values to human readable strings."""
+        table = []
+        for i in xrange(0, upperbound):
+            result = self._run_for_first(
+                'print ((enum {0}){1})'.format(enum, i))
+            parts = result.split(' ')
+            if len(parts) < 3:
+                raise GdbMIException(
+                    "can't parse enum {0} {1}\n".format(enum, i), result)
+            table.append(parts[2].rstrip())
+
+        return table
+
+    def get_func_info(self, address):
+        """Returns the function info at a particular address, specifically line
+        and file."""
+        result = self._run_for_one('info line *0x{0:x}'.format(address))
+        m = re.search(r'(Line \d+ of \\?\".*\\?\")', result)
+        if m is not None:
+            return m.group(0)
+        else:
+            return '(unknown info for address 0x{0:x})'.format(address)
+
+    def get_value_of(self, symbol):
+        """Returns the value of a symbol (in decimal)"""
+        result = self._run_for_one('print /d {0}'.format(symbol))
+        return int(result.split(' ')[-1], 10)
+
+if __name__ == '__main__':
+    if len(sys.argv) != 3:
+        print 'Usage: gdbmi.py gdb_path elf'
+        sys.exit(1)
+
+    gdb_path, elf = sys.argv[1:]
+
+    with GdbMI(gdb_path, elf) as g:
+        print 'GDB Version:', g.version()
+        print 'ion_buffer.heap offset:', g.field_offset('struct ion_buffer', 'heap')
+        print 'atomic_t.counter offset:', g.field_offset('atomic_t', 'counter')
+        print 'sizeof(struct ion_buffer):', g.sizeof('struct ion_buffer')
+        addr = g.address_of('kernel_config_data')
+        print 'address of kernel_config_data:', hex(addr)
+        symbol = g.get_symbol_info(addr)
+        print 'symbol at', hex(addr), ':', symbol.symbol, \
+            'which is in section', symbol.section
diff --git a/linux-ramdump-parser-v2/linux_list.py b/linux-ramdump-parser-v2/linux_list.py
new file mode 100644
index 0000000000000000000000000000000000000000..cb526a30a5ba0a3752a538a1f6b5df3619048fda
--- /dev/null
+++ b/linux-ramdump-parser-v2/linux_list.py
@@ -0,0 +1,66 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from print_out import print_out_str
+
+'''
+struct list_head {
+	struct list_head *next, *prev;
+};
+'''
+
+
+def get_list_offsets(ram_dump):
+    next_offset = ram_dump.field_offset('struct list_head', 'next')
+    prev_offset = ram_dump.field_offset('struct list_head', 'prev')
+    return next_offset, prev_offset
+
+
+class ListWalker(object):
+
+    '''
+    ram_dump: Reference to the ram dump
+    node_addr: The address of the first element of the list
+    list_elem_offset: The offset of the list_head in the structure that this list is container for.
+    next_offset: The offset for the next pointer in the list
+    prev_offset: The offset for the prev pointer in the list
+    '''
+
+    def __init__(self, ram_dump, node_addr, list_elem_offset, next_offset, prev_offset):
+        self.LIST_OFFSETS = [
+            ('((struct list_head *)0x0)', 'next', 0, 0),
+            ('((struct list_head *)0x0)', 'prev', 0, 0),
+        ]
+        self.LIST_NEXT_IDX = 0
+        self.LIST_PREV_IDX = 1
+
+        self.ram_dump = ram_dump
+        self.next_offset = next_offset
+        self.prev_offset = prev_offset
+        self.list_elem_offset = list_elem_offset
+
+        self.last_node = node_addr
+        self.seen_nodes = []
+
+    def walk(self, node_addr, func):
+        if node_addr != 0:
+            func(node_addr - self.list_elem_offset)
+
+            next_node_addr = node_addr + self.next_offset
+            next_node = self.ram_dump.read_word(next_node_addr)
+
+            if next_node != self.last_node:
+                if next_node in self.seen_nodes:
+                    print_out_str(
+                        '[!] WARNING: Cycle found in attach list for IOMMU domain. List is corrupted!')
+                else:
+                    self.seen_nodes.append(node_addr)
+                    self.walk(next_node, func)
diff --git a/linux-ramdump-parser-v2/mm.py b/linux-ramdump-parser-v2/mm.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e6f6ff86d1904865760a0d5428e2486e411803a
--- /dev/null
+++ b/linux-ramdump-parser-v2/mm.py
@@ -0,0 +1,216 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+
+def page_buddy(ramdump, page):
+    mapcount_offset = ramdump.field_offset('struct page', '_mapcount')
+    val = ramdump.read_word(page + mapcount_offset)
+    # -128 is the magic for in the buddy allocator
+    return val == 0xffffff80
+
+
+def page_zonenum(page_flags):
+    # save this in a variable somewhere...
+    return (page_flags >> 26) & 3
+
+
+def page_to_nid(page_flags):
+    return 0
+
+
+def page_zone(ramdump, page):
+    contig_page_data = ramdump.addr_lookup('contig_page_data')
+    node_zones_offset = ramdump.field_offset(
+        'struct pglist_data', 'node_zones')
+    page_flags_offset = ramdump.field_offset('struct page', 'flags')
+    zone_size = ramdump.sizeof('struct zone')
+    page_flags = ramdump.read_word(page + page_flags_offset)
+    if page_flags is None:
+        return None
+    zone = contig_page_data + node_zones_offset + \
+        (page_zonenum(page_flags) * zone_size)
+    return zone
+
+
+def zone_is_highmem(ramdump, zone):
+    if zone is None:
+        return False
+    # not at all how linux does it but it works for our purposes...
+    zone_name_offset = ramdump.field_offset('struct zone', 'name')
+    zone_name_addr = ramdump.read_word(zone + zone_name_offset)
+    if zone_name_addr is None:
+        return False
+    zone_name = ramdump.read_cstring(zone_name_addr, 48)
+    if zone_name is None:
+        # XXX do something?
+        return False
+    if zone_name == 'HighMem':
+        return True
+    else:
+        return False
+
+
+def hash32(val, bits):
+    chash = c_uint(val * 0x9e370001).value
+    return chash >> (32 - bits)
+
+
+def page_slot(ramdump, page):
+    hashed = hash32(page, 7)
+    htable = ramdump.addr_lookup('page_address_htable')
+    htable_size = ramdump.sizeof('page_address_htable[0]')
+    return htable + htable_size * hashed
+
+
+def page_to_section(page_flags):
+    # again savefn8n variable
+    return (page_flags >> 28) & 0xF
+
+
+def nr_to_section(ramdump, sec_num):
+    memsection_struct_size = ramdump.sizeof('struct mem_section')
+    sections_per_root = 4096 / memsection_struct_size
+    sect_nr_to_root = sec_num / sections_per_root
+    masked = sec_num & (sections_per_root - 1)
+    mem_section_addr = ramdump.addr_lookup('mem_section')
+    mem_section = ramdump.read_word(mem_section_addr)
+    if mem_section is None:
+        return None
+    return mem_section + memsection_struct_size * (sect_nr_to_root * sections_per_root + masked)
+
+
+def section_mem_map_addr(ramdump, section):
+    map_offset = ramdump.field_offset('struct mem_section', 'section_mem_map')
+    result = ramdump.read_word(section + map_offset)
+    return result & ~((1 << 2) - 1)
+
+
+def pfn_to_section_nr(pfn):
+    return pfn >> (28 - 12)
+
+
+def pfn_to_section(ramdump, pfn):
+    return nr_to_section(ramdump, pfn_to_section_nr(pfn))
+
+
+def pfn_to_page_sparse(ramdump, pfn):
+    sec = pfn_to_section(ramdump, pfn)
+    sizeof_page = ramdump.sizeof('struct page')
+    return section_mem_map_addr(ramdump, sec) + pfn * sizeof_page
+
+
+def page_to_pfn_sparse(ramdump, page):
+    page_flags_offset = ramdump.field_offset('struct page', 'flags')
+    sizeof_page = ramdump.sizeof('struct page')
+    flags = ramdump.read_word(page + page_flags_offset)
+    if flags is None:
+        return 0
+    section = page_to_section(flags)
+    nr = nr_to_section(ramdump, section)
+    addr = section_mem_map_addr(ramdump, nr)
+    # divide by struct page size for division fun
+    return (page - addr) / sizeof_page
+
+
+def page_to_pfn_flat(ramdump, page):
+    mem_map_addr = ramdump.addr_lookup('mem_map')
+    mem_map = ramdump.read_word(mem_map_addr)
+    page_size = ramdump.sizeof('struct page')
+    # XXX Needs to change for LPAE
+    pfn_offset = ramdump.phys_offset >> 12
+    return ((page - mem_map) / page_size) + pfn_offset
+
+
+def pfn_to_page_flat(ramdump, pfn):
+    mem_map_addr = ramdump.addr_lookup('mem_map')
+    mem_map = ramdump.read_word(mem_map_addr)
+    page_size = ramdump.sizeof('struct page')
+    # XXX Needs to change for LPAE
+    pfn_offset = ramdump.phys_offset >> 12
+    return mem_map + (pfn * page_size) - pfn_offset
+
+
+def page_to_pfn(ramdump, page):
+    if ramdump.is_config_defined('CONFIG_SPARSEMEM'):
+        return page_to_pfn_sparse(ramdump, page)
+    else:
+        return page_to_pfn_flat(ramdump, page)
+
+
+def pfn_to_page(ramdump, pfn):
+    if ramdump.is_config_defined('CONFIG_SPARSEMEM'):
+        return pfn_to_page_sparse(ramdump, pfn)
+    else:
+        return pfn_to_page_flat(ramdump, pfn)
+
+
+def sparsemem_lowmem_page_address(ramdump, page):
+    membank1_start = ramdump.read_word(ramdump.addr_lookup('membank1_start'))
+    membank0_size = ramdump.read_word(ramdump.addr_lookup('membank0_size'))
+    # XXX currently magic
+    membank0_phys_offset = ramdump.phys_offset
+    membank0_page_offset = 0xc0000000
+    membank1_phys_offset = membank1_start
+    membank1_page_offset = membank0_page_offset + membank0_size
+    phys = page_to_pfn(ramdump, page) << 12
+    if phys >= membank1_start:
+        return phys - membank1_phys_offset + membank1_page_offset
+    else:
+        return phys - membank0_phys_offset + membank0_page_offset
+
+
+def dont_map_hole_lowmem_page_address(ramdump, page):
+    phys = page_to_pfn(ramdump, page) << 12
+    hole_end_addr = ramdump.addr_lookup('memory_hole_end')
+    hole_offset_addr = ramdump.addr_lookup('memory_hole_offset')
+    hole_end = ramdump.read_word(hole_end_addr)
+    hole_offset = ramdump.read_word(hole_offset_addr)
+    if hole_end != 0 and phys >= hole_end:
+        return phys - hole_end + hole_offset + 0xc0000000
+    else:
+        return phys - ramdump.phys_offset + 0xc0000000
+
+
+def normal_lowmem_page_address(ramdump, page):
+    phys = page_to_pfn(ramdump, page) << 12
+    return phys - ramdump.phys_offset + 0xc0000000
+
+
+def lowmem_page_address(ramdump, page):
+    if ramdump.is_config_defined('CONFIG_SPARSEMEM'):
+        return sparsemem_lowmem_page_address(ramdump, page)
+    elif ramdump.is_config_defined('CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0'):
+        return dont_map_hole_lowmem_page_address(ramdump, page)
+    else:
+        return normal_lowmem_page_address(ramdump, page)
+
+
+def page_address(ramdump, page):
+    if not zone_is_highmem(ramdump, page_zone(ramdump, page)):
+        return lowmem_page_address(ramdump, page)
+
+    pas = page_slot(ramdump, page)
+    lh_offset = ramdump.field_offset('struct page_address_slot', 'lh')
+    start = pas + lh_offset
+    pam = start
+    while True:
+        pam = pam - lh_offset
+        pam_page_offset = ramdump.field_offset(
+            'struct page_address_map', 'page')
+        pam_virtual_offset = ramdump.field_offset(
+            'struct page_address_map', 'virtual')
+        pam_page = ramdump.read_word(pam + pam_page_offset)
+        if pam_page == page:
+            ret = ramdump.read_word(pam + pam_virtual_offset)
+            return ret
+        pam = ramdump.read_word(pam + lh_offset)
+        if pam == start:
+            return None
diff --git a/linux-ramdump-parser-v2/mmu.py b/linux-ramdump-parser-v2/mmu.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc18400d43f18580d0a2113ab994fd7731c1f2a8
--- /dev/null
+++ b/linux-ramdump-parser-v2/mmu.py
@@ -0,0 +1,332 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from bitops import bm, bvalsel
+from register import Register
+
+
+class MMU(object):
+
+    """Represents an MMU. Does virtual-to-physical address lookups,
+    caching the results in a TLB.
+
+    This is an abstract class that should not be used
+    directly. Concrete subclasses should override the following
+    methods:
+
+    - load_page_tables()
+
+    - page_table_walk(addr)
+
+    - dump_page_tables(file_object)
+
+
+    Interesting properties that will be set for usage in derived
+    classes:
+
+    - ramdump:: The RamDump instance being parsed
+
+    """
+
+    def __init__(self, ramdump):
+        self._tlb = {}
+        self.ramdump = ramdump
+        self.ttbr = None
+        self.load_page_tables()
+
+    def virt_to_phys(self, addr, skip_tlb=False, save_in_tlb=True):
+        if addr is None:
+            return None
+
+        if not skip_tlb:
+            if addr in self._tlb:
+                return self._tlb[addr]
+
+        phys_addr = self.page_table_walk(addr)
+
+        if save_in_tlb:
+            self._tlb[addr] = phys_addr
+
+        return phys_addr
+
+    def load_page_tables(self):
+        raise NotImplementedError
+
+    def page_table_walk(self, virt):
+        raise NotImplementedError
+
+    def dump_page_tables(self, f):
+        raise NotImplementedError
+
+
+class Armv7MMU(MMU):
+
+    """An MMU for ARMv7 (no LPAE)."""
+
+    def load_page_tables(self):
+        self.global_page_table = [0 for i in range(4096)]
+        self.secondary_page_tables = [
+            [0 for col in range(256)] for row in range(4096)]
+
+        msm_ttbr0 = self.ramdump.phys_offset + 0x4000
+        self.ttbr = msm_ttbr0
+        virt_address = 0x0
+        gb_i = 0
+        se_i = 0
+        for l1_pte_ptr in range(msm_ttbr0, msm_ttbr0 + (4096 * 4), 4):
+            l1_pte = self.ramdump.read_word(l1_pte_ptr, False)
+            self.global_page_table[gb_i] = l1_pte
+            if l1_pte is None:
+                gb_i += 1
+                continue
+            if (l1_pte & 3) == 0 or (l1_pte & 3) == 3:
+                for k in range(0, 256):
+                    virt_address += 0x1000
+            elif (l1_pte & 3) == 2:
+                if ((l1_pte & 0x40000) == 0):
+                    l1_pte_counter = l1_pte & 0xFFF00000
+                    for k in range(0, 256):
+                        virt_address += 0x1000
+                        l1_pte_counter += 0x1000
+                else:
+                    gb_i += 1
+                    continue
+            elif (l1_pte & 3) == 1:
+                l2_pt_desc = l1_pte
+                l2_pt_base = l2_pt_desc & (~0x3ff)
+                for l2_pte_ptr in range(l2_pt_base, l2_pt_base + (256 * 4), 4):
+                    virt_address += 0x1000
+                    l2_pt_entry = self.ramdump.read_word(l2_pte_ptr, False)
+                    self.secondary_page_tables[gb_i][se_i] = l2_pt_entry
+                    se_i += 1
+                se_i = 0
+            gb_i += 1
+
+    def page_table_walk(self, virt):
+        global_offset = bvalsel(31, 20, virt)
+        l1_pte = self.global_page_table[global_offset]
+        bit18 = (l1_pte & 0x40000) >> 18
+        if (bvalsel(1, 0, l1_pte) == 1):
+            l2_offset = bvalsel(19, 12, virt)
+            l2_pte = self.secondary_page_tables[global_offset][l2_offset]
+            if l2_pte is None:
+                return None
+            if (bvalsel(1, 0, l2_pte) == 2) or (bvalsel(1, 0, l2_pte) == 3):
+                entry4kb = (l2_pte & bm(31, 12)) + bvalsel(11, 0, virt)
+                return entry4kb
+            elif (bvalsel(1, 0, l2_pte) == 1):
+                entry64kb = (l2_pte & bm(31, 16)) + bvalsel(15, 0, virt)
+                return entry64kb
+        if (bvalsel(1, 0, l1_pte) == 2):
+            onemb_entry = bm(31, 20) & l1_pte
+            onemb_entry += bvalsel(19, 0, virt)
+            return onemb_entry
+
+        return 0
+
+    def dump_page_tables(self, f):
+        f.write(
+            'Dumping page tables is not currently supported for Armv7MMU\n')
+        f.flush()
+
+
+class Armv7LPAEMMU(MMU):
+
+    """An MMU for ARMv7 (with LPAE)"""
+    # Descriptor types
+    DESCRIPTOR_INVALID = 0x0
+    DESCRIPTOR_BLOCK = 0x1
+    DESCRIPTOR_TABLE = 0x3
+    TL_DESCRIPTOR_RESERVED = 0x1
+    TL_DESCRIPTOR_PAGE = 0x3
+
+    def do_fl_sl_level_lookup(self, table_base_address, table_index,
+                              input_addr_split, block_split):
+        descriptor, addr = self.do_level_lookup(
+            table_base_address, table_index,
+            input_addr_split)
+        if descriptor.dtype == Armv7LPAEMMU.DESCRIPTOR_BLOCK:
+            descriptor.add_field('output_address', (39, block_split))
+        elif descriptor.dtype == Armv7LPAEMMU.DESCRIPTOR_TABLE:
+            # we have bits 39:12 of the next-level table in
+            # next_level_base_addr_upper
+            descriptor.add_field('next_level_base_addr_upper', (39, 12))
+        else:
+            raise Exception(
+                'Invalid stage 1 first- or second-level translation\ndescriptor: (%s)\naddr: (%s)'
+                % (str(descriptor), str(addr))
+            )
+        return descriptor
+
+    def do_fl_level_lookup(self, table_base_address, table_index,
+                           input_addr_split):
+        return do_fl_sl_level_lookup(table_base_address, table_index,
+                                     input_addr_split, 30)
+
+    def do_sl_level_lookup(self, table_base_address, table_index):
+        return do_fl_sl_level_lookup(table_base_address, table_index,
+                                     12, 21)
+
+    def do_tl_level_lookup(self, table_base_address, table_index):
+        descriptor, addr = self.do_level_lookup(
+            table_base_address, table_index, 12)
+        if descriptor.dtype == Armv7LPAEMMU.TL_DESCRIPTOR_PAGE:
+            descriptor.add_field('output_address', (39, 12))
+        else:
+            raise Exception(
+                'Invalid stage 1 third-level translation\ndescriptor: (%s)\naddr: (%s)'
+                % (str(descriptor), str(addr))
+            )
+        return descriptor
+
+    def do_level_lookup(self, table_base_address, table_index,
+                        input_addr_split):
+        """Does a base + index descriptor lookup.
+
+        Returns a tuple with the Register object representing the found
+        descriptor and a Register object representing the the computed
+        descriptor address.
+
+        """
+        n = input_addr_split
+        # these Registers are overkill but nice documentation:).
+        table_base = Register(table_base_address, base=(39, n))
+        descriptor_addr = Register(base=(39, n),
+                                   offset=(n - 1, 3))
+        descriptor_addr.base = table_base.base
+        descriptor_addr.offset = table_index
+        descriptor_val = self.read_phys_dword(descriptor_addr.value)
+        descriptor = Register(descriptor_val,
+                              dtype=(1, 0))
+        return descriptor, descriptor_addr
+
+    def block_or_page_desc_2_phys(self, desc, virt_r, n):
+        phys = Register(output_address=(39, n),
+                        page_offset=(n - 1, 0))
+        phys.output_address = desc.output_address
+        virt_r.add_field('rest', (n - 1, 0))
+        phys.page_offset |= virt_r.rest
+        return phys.value
+
+    def fl_block_desc_2_phys(self, desc, virt_r):
+        """Block descriptor to physical address."""
+        return self.block_or_page_desc_2_phys(desc, virt_r, 30)
+
+    def sl_block_desc_2_phys(self, desc, virt_r):
+        """Block descriptor to physical address."""
+        return self.block_or_page_desc_2_phys(desc, virt_r, 21)
+
+    def tl_page_desc_2_phys(self, desc, virt_r):
+        """Page descriptor to physical address."""
+        return self.block_or_page_desc_2_phys(desc, virt_r, 12)
+
+    def read_phys_dword(self, physaddr):
+        return self.ramdump.read_dword(physaddr, virtual=False)
+
+    def load_page_tables(self):
+        pass
+
+    def page_table_walk(self, virt):
+        text_offset = 0x8000
+        pg_dir_size = 0x5000    # 0x4000 for non-LPAE
+        swapper_pg_dir_addr = self.ramdump.phys_offset + \
+            text_offset - pg_dir_size
+
+        # We deduce ttbr1 and ttbcr.t1sz based on the value of
+        # PAGE_OFFSET. This is based on v7_ttb_setup in
+        # arch/arm/mm/proc-v7-3level.S:
+
+        # * TTBR0/TTBR1 split (PAGE_OFFSET):
+        # *   0x40000000: T0SZ = 2, T1SZ = 0 (not used)
+        # *   0x80000000: T0SZ = 0, T1SZ = 1
+        # *   0xc0000000: T0SZ = 0, T1SZ = 2
+        ttbr = swapper_pg_dir_addr
+        self.ttbr = ttbr
+        if self.ramdump.page_offset == 0x40000000:
+            t1sz = 0
+            initial_lkup_level = 1
+        elif self.ramdump.page_offset == 0x80000000:
+            t1sz = 1
+            initial_lkup_level = 1
+        elif self.ramdump.page_offset == 0xc0000000:
+            t1sz = 2
+            # need to fixup ttbr1 since we'll be skipping the
+            # first-level lookup (see v7_ttb_setup):
+            # /* PAGE_OFFSET == 0xc0000000, T1SZ == 2 */
+            # add      \ttbr1, \ttbr1, #4096 * (1 + 3) @ only L2 used, skip
+            # pgd+3*pmd
+            ttbr += (4096 * (1 + 3))
+            initial_lkup_level = 2
+        else:
+            raise Exception(
+                'Invalid phys_offset for page_table_walk: 0x%x'
+                % self.ramdump.page_offset)
+
+        if initial_lkup_level == 1:
+            # see the ARMv7 ARM B3.6.6 (rev 0406C.b):
+            input_addr_split = 5 - t1sz
+            if input_addr_split not in [4, 5]:
+                raise Exception("Invalid stage 1 first-level `n' value: 0x%x"
+                                % input_addr_split)
+            virt_r = Register(virt,
+                              fl_index=(input_addr_split + 26, 30),
+                              sl_index=(29, 21),
+                              tl_index=(20, 12),
+                              page_index=(11, 0))
+            fl_desc = self.do_fl_level_lookup(
+                ttbr, virt_r.fl_index, input_addr_split)
+
+            # if we got a block descriptor we're done:
+            if fl_desc.dtype == Armv7LPAEMMU.DESCRIPTOR_BLOCK:
+                return self.fl_block_desc_2_phys(fl_desc, virt_r)
+
+            base = Register(base=(39, 12))
+            base.base = fl_desc.next_level_base_addr_upper
+            sl_desc = self.do_sl_level_lookup(
+                base.value, virt_r.sl_index)
+
+        elif initial_lkup_level == 2:
+            # see the ARMv7 ARM B3.6.6 (rev 0406C.b):
+            input_addr_split = 14 - t1sz
+            if input_addr_split not in range(7, 13):
+                raise Exception("Invalid stage 1 second-level (initial) `n' value: 0x%x"
+                                % input_addr_split)
+            virt_r = Register(virt,
+                              sl_index=(input_addr_split + 17, 21),
+                              tl_index=(20, 12),
+                              page_index=(11, 0))
+            try:
+                sl_desc = self.do_fl_sl_level_lookup(
+                    ttbr, virt_r.sl_index, input_addr_split, 21)
+            except:
+                return None
+        else:
+            raise Exception('Invalid initial lookup level (0x%x)' %
+                            initial_lkup_level)
+
+        # if we got a block descriptor we're done:
+        if sl_desc.dtype == Armv7LPAEMMU.DESCRIPTOR_BLOCK:
+            return self.sl_block_desc_2_phys(sl_desc, virt_r)
+
+        base = Register(base=(39, 12))
+        base.base = sl_desc.next_level_base_addr_upper
+        try:
+            tl_desc = self.do_tl_level_lookup(
+                base.value, virt_r.tl_index)
+        except:
+            return None
+
+        return self.tl_page_desc_2_phys(tl_desc, virt_r)
+
+    def dump_page_tables(self, f):
+        f.write(
+            'Dumping page tables is not currently supported for Armv7LPAEMMU\n')
+        f.flush()
diff --git a/linux-ramdump-parser-v2/parser_util.py b/linux-ramdump-parser-v2/parser_util.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b03cba10a1bff24837cb8a658a8ded7be7b165a
--- /dev/null
+++ b/linux-ramdump-parser-v2/parser_util.py
@@ -0,0 +1,156 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import os
+import platform
+import glob
+import re
+
+_parsers = []
+
+
+class ParserConfig(object):
+
+    """Class to encapsulate a RamParser its desired setup (command-line
+    options, etc)."""
+
+    def __init__(self, cls, longopt, desc, shortopt, optional):
+        self.cls = cls
+        self.longopt = longopt
+        self.desc = desc
+        self.shortopt = shortopt
+        self.optional = optional
+
+
+def register_parser(longopt, desc, shortopt=None, optional=False):
+    """Decorator to register a parser class (a class that inherits from
+    RamParser) with the parsing framework. By using this decorator
+    your parser will automatically be hooked up to the command-line
+    parsing code.
+
+    This makes it very easy and clean to add a new parser:
+
+      o Drop a new file in parsers that defines a class that inherits
+        from RamParser
+
+      o Decorate your class with @register_parser
+
+      o Define a `parse' method for your class
+
+    All of the command line argument handling and invoking the parse
+    method of your parser will then be handled automatically.
+
+    Required arguments:
+
+    - longopt:: The longopt command line switch for this parser
+
+    - desc:: A short description of the parser (also shown in the
+      help-text associated with the longopt)
+
+    Optional arguments:
+
+    - shortopt:: The shortopt command line switch for this parser
+
+    - optional:: Indicates the parser is optional and should not be run with
+      --everything
+
+    """
+    def wrapper(cls):
+        if cls in [p.cls for p in _parsers]:
+            raise Exception(cls + ' is already registered!')
+        _parsers.append(ParserConfig(cls, longopt, desc, shortopt, optional))
+        return cls
+    return wrapper
+
+
+def get_parsers():
+    """Imports everyone under the `parsers' directory. It is expected that
+    the parsers under the parsers directory will be a collection of
+    classes that subclass RamParser and use the register_parser
+    decorator to register themselves with the parser
+    framework. Therefore, importing all the modules under `parsers'
+    should have the side-effect of populating the (internal to
+    parser_util) _parsers list with the discovered parsers.
+
+    Returns the list of ParserConfig instances built as a side-effect
+    of the importing.
+
+    """
+    parsers_dir = os.path.join(os.path.dirname(__file__), 'parsers')
+    for f in glob.glob(os.path.join(parsers_dir, '*.py')):
+        modname_ext = os.path.basename(f)
+        if modname_ext == '__init__.py':
+            continue
+        modname = 'parsers.' + os.path.splitext(modname_ext)[0]
+        # if the module contains a class (or classes) that are
+        # decorated with `register_parser' then the following import
+        # will have the side-effect of adding that class (encapsulated
+        # in a ParserConfig object) to the _parsers list. Note that
+        # this import is effectively a noop if the module has already
+        # been imported, so there's no harm in calling get_parsers
+        # multiple times.
+        __import__(modname)
+    return _parsers
+
+
+class RamParser(object):
+
+    """Base class for implementing ramdump parsers. New parsers should inherit
+    from this class and define a `parse' method.
+
+    Interesting properties that will be set for usage in derived
+    classes:
+
+    - ramdump:: The RamDump instance being parsed
+
+    """
+
+    def __init__(self, ramdump):
+        self.ramdump = ramdump
+
+    def parse(self):
+        raise NotImplementedError
+
+
+def which(program):
+    """Just like which(1).
+
+    Searches the PATH environment variable for a directory containing
+    program.
+
+    """
+    for path in os.environ['PATH'].split(os.pathsep):
+        exe_file = os.path.join(path, program)
+        if os.access(exe_file, os.X_OK):
+            return exe_file
+
+    return None
+
+
+def get_system_type():
+    """Returns a "normalized" version of platform.system (transforming CYGWIN
+    to Windows, for example).
+
+    Returns None if not a supported platform.
+
+    """
+    plat = platform.system()
+    if plat == 'Windows':
+        return 'Windows'
+    if re.search('CYGWIN', plat) is not None:
+        # On certain installs, the default windows shell
+        # runs cygwin. Treat cygwin as windows for this
+        # purpose
+        return 'Windows'
+    if plat == 'Linux':
+        return 'Linux'
+    if plat == 'Darwin':
+        return 'Darwin'
diff --git a/linux-ramdump-parser-v2/parsers/__init__.py b/linux-ramdump-parser-v2/parsers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/linux-ramdump-parser-v2/parsers/cachedump.py b/linux-ramdump-parser-v2/parsers/cachedump.py
new file mode 100644
index 0000000000000000000000000000000000000000..76570005cc558edfe03dae95e6e73eeefa52a761
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/cachedump.py
@@ -0,0 +1,124 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import struct
+
+from parser_util import register_parser, RamParser
+from print_out import print_out_str
+
+# assuming cache way size of 8, fix this for badger probably
+cache_way = 8
+
+
+def save_l1_dump(ram_dump, cache_base, size):
+    with ram_dump.open_file('l1_cache_dump.bin') as cache_file:
+
+        for i in range(0, size):
+            val = ram_dump.read_byte(cache_base + i, False)
+            cache_file.write(struct.pack('<B', val))
+        print_out_str('--- Wrote cache dump to l1_cache_dump.bin')
+
+
+def parse_cache_dump(ram_dump, cache_base):
+
+    magic_num_offset = ram_dump.field_offset(
+        'struct l2_cache_dump', 'magic_number')
+    version_offset = ram_dump.field_offset('struct l2_cache_dump', 'version')
+    line_size_offset = ram_dump.field_offset(
+        'struct l2_cache_dump', 'line_size')
+    total_lines_offset = ram_dump.field_offset(
+        'struct l2_cache_dump', 'total_lines')
+    cache_offset_struct = ram_dump.field_offset(
+        'struct l2_cache_dump', 'cache')
+    l2dcrtr0_offset_struct = ram_dump.field_offset(
+        'struct l2_cache_line_dump', 'l2dcrtr0_val')
+    l2dcrtr1_offset_struct = ram_dump.field_offset(
+        'struct l2_cache_line_dump', 'l2dcrtr1_val')
+    cache_line_data_offset_struct = ram_dump.field_offset(
+        'struct l2_cache_line_dump', 'cache_line_data')
+    cache_line_struct_size = ram_dump.sizeof('struct l2_cache_line_dump')
+
+    magic = ram_dump.read_word(cache_base + magic_num_offset, False)
+    version = ram_dump.read_word(cache_base + version_offset, False)
+    line_size = ram_dump.read_word(cache_base + line_size_offset, False)
+    total_lines = ram_dump.read_word(cache_base + total_lines_offset, False)
+    cache = ram_dump.read_word(cache_base + cache_offset_struct, False)
+
+    cache_file = ram_dump.open_file('l2_cache_dump.txt')
+
+    cache_file.write('Magic = {0:x}\n'.format(magic))
+    cache_file.write('version = {0:x}\n'.format(version))
+    cache_file.write('line size = {0:x}\n'.format(line_size))
+
+    select = 0
+    lines = total_lines / cache_way
+
+    header_str = '({0:4},{1:1}) {2:5} {3:8} '.format(
+        'Set', 'Way', 'valid', 'Address')
+    # currently assumes 32 bit word like everything else...
+    for i in range(0, 32):
+        header_str = header_str + '{0:8} '.format('Word{0}'.format(i))
+
+    header_str = header_str + '{0:8} {1:8}\n'.format('L2DCRTR0', 'L2DCRTR0')
+
+    cache_ptr = cache_base + cache_offset_struct
+
+    for i in range(0, lines):
+
+        cache_file.write(header_str)
+
+        for j in range(0, cache_way):
+            cache_line_ptr = cache_ptr + (i * cache_way + j) * line_size
+
+            l2dcrtr0_val = ram_dump.read_word(
+                cache_line_ptr + l2dcrtr0_offset_struct, False)
+            l2dcrtr1_val = ram_dump.read_word(
+                cache_line_ptr + l2dcrtr1_offset_struct, False)
+
+            # this is valid for krait, will probably need to be more generic
+
+            addr = l2dcrtr1_val & 0xFFFE0000
+            addr = addr | (select & 0x0001ff80)
+            valid = (l2dcrtr0_val >> 14) & 0x3
+
+            out_str = '({0:4},{1:1}) {2:5} {3:8x} '.format(i, j, valid, addr)
+
+            cache_line_data_ptr = cache_line_ptr + \
+                cache_line_data_offset_struct
+
+            for k in range(0, 32):
+                out_str = out_str + \
+                    '{0:0=8x} '.format(
+                        ram_dump.read_word(cache_line_data_ptr + 4 * k, False))
+
+            out_str = out_str + \
+                '{0:0=8x} {1:0=8x}\n'.format(l2dcrtr0_val, l2dcrtr1_val)
+
+            cache_file.write(out_str)
+            select = select + 0x10
+
+    cache_file.close()
+    print_out_str('--- Wrote cache dump to l2_cache_dump.txt')
+
+
+@register_parser('--print-cache-dump', 'Print L2 cache dump', optional=True)
+class CacheDump(RamParser):
+
+    def parse(self):
+        if not self.ramdump.is_config_defined('CONFIG_MSM_CACHE_DUMP'):
+            print_out_str(
+                '!!! Cache dumping was not enabled. No cache will be dumped')
+            return
+
+        cache_base_addr = self.ramdump.addr_lookup('l2_dump')
+        cache_base = self.ramdump.read_word(cache_base_addr)
+
+        parse_cache_dump(self.ramdump, cache_base)
diff --git a/linux-ramdump-parser-v2/parsers/cpu_state.py b/linux-ramdump-parser-v2/parsers/cpu_state.py
new file mode 100644
index 0000000000000000000000000000000000000000..97be12ff0f339f02603f9e5db8fa33ad63895f01
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/cpu_state.py
@@ -0,0 +1,65 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from itertools import cycle
+
+from parser_util import register_parser, RamParser
+from print_out import print_out_str
+
+
+@register_parser('--cpu-state', "Reads register values of non-panic'ing CPUs")
+class CpuState(RamParser):
+
+    def parse(self):
+        regs_before_stop_addr = self.ramdump.addr_lookup('regs_before_stop')
+        if regs_before_stop_addr is None:
+            print_out_str('regs_before_stop not found. Nothing to do.')
+            return
+
+        # see pt_regs and associated #defines in
+        # arch/arm/include/asm/ptrace.h
+        regs = (
+            'r0',
+            'r1',
+            'r2',
+            'r3',
+            'r4',
+            'r5',
+            'r6',
+            'r7',
+            'r8',
+            'r9',
+            'r10',
+            'fp',
+            'ip',
+            'sp',
+            'lr',
+            'pc',
+            'cpsr',
+        )
+
+        max_len = max([len(s) for s in regs])
+
+        for cpu in self.ramdump.iter_cpus():
+            print_out_str('CPU %d' % cpu)
+            lines = []
+            for index, reg in enumerate(regs):
+                reg_addr = self.ramdump.array_index(
+                    regs_before_stop_addr, 'unsigned long', index)
+                reg_val = self.ramdump.read_word(reg_addr, cpu=cpu)
+                lines.append(
+                    '   {0:{width}} = 0x{1:x}'.format(reg, reg_val, width=max_len))
+
+            c = cycle([', ', ', ', ', ', '\n'])
+            output = ''
+            for line in lines:
+                output += line + next(c)
+            print_out_str(output)
diff --git a/linux-ramdump-parser-v2/parsers/debug_image.py b/linux-ramdump-parser-v2/parsers/debug_image.py
new file mode 100644
index 0000000000000000000000000000000000000000..89576fe28a0b2e008a763bab0a466caf3a3af1c4
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/debug_image.py
@@ -0,0 +1,190 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import struct
+
+from parser_util import register_parser, RamParser
+from print_out import print_out_str
+from qdss import QDSSDump
+from cachedump import save_l1_dump, parse_cache_dump
+
+QDSS_MAGIC = 0x5D1DB1Bf
+
+print_table = {
+    'MSM_CPU_CTXT': 'parse_cpu_ctx',
+    'MSM_L1_CACHE': 'parse_l1_cache',
+    'MSM_L2_CACHE': 'parse_l2_cache',
+    'MSM_OCMEM': 'parse_ocmem',
+    'MSM_TMC0_REG': 'parse_qdss_common',
+    'MSM_TMC_ETFETB': 'parse_qdss_common',
+    'MSM_TMC1_REG': 'parse_qdss_common',
+    'MSM_ETM0_REG': 'parse_qdss_common',
+    'MSM_ETM1_REG': 'parse_qdss_common',
+    'MSM_ETM2_REG': 'parse_qdss_common',
+    'MSM_ETM3_REG': 'parse_qdss_common',
+}
+
+tag_to_field_name = {
+    'MSM_TMC0_REG': 'tmc_etr_start',
+    'MSM_TMC_ETFETB': 'etf_start',
+    'MSM_TMC1_REG': 'tmc_etf_start',
+    'MSM_ETM0_REG': 'etm_regs0',
+    'MSM_ETM1_REG': 'etm_regs1',
+    'MSM_ETM2_REG': 'etm_regs2',
+    'MSM_ETM3_REG': 'etm_regs3',
+}
+
+
+@register_parser('--parse-debug-image', 'Parse the debug image and associated information')
+class DebugImage(RamParser):
+
+    def __init__(self, *args):
+        super(DebugImage, self).__init__(*args)
+        self.qdss = QDSSDump()
+        self.name_lookup_table = []
+
+    def parse_cpu_ctx(self, start, end, tag):
+        print_out_str(
+            'Parsing CPU context start {0:x} end {1:x}'.format(start, end))
+        # For historical reasons, we can't rely on the magic number to indicate if there
+        # is context dumped. Check the magic number here instead
+        magic = self.ramdump.read_word(start, False)
+        if magic is None:
+            print_out_str(
+                "!!! Address {0:x} is bogus! Can't parse!".format(start))
+            return
+
+        if magic != 0x44434151:
+            print_out_str(
+                "!!! Magic {0:x} doesn't match! No context was dumped!".format(magic))
+            return
+
+        regs = TZRegDump(self.ramdump)
+        regs.init_regs(start)
+        for i in range(regs.ncores):
+            regs.dump_core_pc(i)
+        regs.dump_all_regs()
+
+    def parse_l2_cache(self, start, end, tag):
+        print_out_str(
+            'Parsing L2 cache context start {0:x} end {1:x}'.format(start, end))
+        magic = self.ramdump.read_word(start, False)
+        if magic is None:
+            print_out_str(
+                "!!! Address {0:x} is bogus! Can't parse!".format(start))
+            return
+
+        if magic != 0xcac1ecac:
+            print_out_str(
+                "!!! Magic {0:x} doesn't match! No cache was dumped!".format(magic))
+            return
+
+        parse_cache_dump(self.ramdump, start)
+
+    def parse_l1_cache(self, start, end, tag):
+        print_out_str(
+            'Parsing L1 cache context start {0:x} end {1:x}'.format(start, end))
+        magic = self.ramdump.read_word(start, False)
+        if magic is None:
+            print_out_str(
+                "!!! Address {0:x} is bogus! Can't parse!".format(start))
+            return
+
+        if magic != 0x314C4151:
+            print_out_str(
+                "!!! Magic {0:X} doesn't match! No cache was dumped!".format(magic))
+            return
+        print_out_str('Saving L1 cache')
+        save_l1_dump(self.ramdump, start, end - start)
+
+    def parse_ocmem(self, start, end, tag):
+        print_out_str(
+            '[!!!] Parsing not implemented yet start {0:x} end {1:x}'.format(start, end))
+
+    def parse_qdss_common(self, start, end, tag):
+        print_out_str(
+            'Parsing {0} context start {1:x} end {2:x}'.format(tag, start, end))
+        magic = self.ramdump.read_word(start, False)
+        if magic is None:
+            print_out_str(
+                "!!! Address {0:x} is bogus! Can't parse!".format(start))
+            return
+
+        if magic != QDSS_MAGIC:
+            print_out_str(
+                "!!! Magic {0:X} doesn't match! Tracing was not dumped!".format(magic))
+            return
+
+        setattr(self.qdss, tag_to_field_name[tag], start + 4096)
+
+    def parse(self):
+        if not self.ramdump.is_config_defined('CONFIG_MSM_MEMORY_DUMP'):
+            print_out_str(
+                '!!! Debug image was not enabled. No debug dump will be provided')
+            return
+
+        out_dir = self.ramdump.outdir
+        self.name_lookup_table = self.ramdump.gdbmi.get_enum_lookup_table(
+            'dump_client_type', 32)
+        dump_table_ptr_offset = self.ramdump.field_offset(
+            'struct msm_memory_dump', 'dump_table_ptr')
+        version_offset = self.ramdump.field_offset(
+            'struct msm_dump_table', 'version')
+        num_entries_offset = self.ramdump.field_offset(
+            'struct msm_dump_table', 'num_entries')
+        client_entries_offset = self.ramdump.field_offset(
+            'struct msm_dump_table', 'client_entries')
+        id_offset = self.ramdump.field_offset('struct msm_client_dump', 'id')
+        start_addr_offset = self.ramdump.field_offset(
+            'struct msm_client_dump', 'start_addr')
+        end_addr_offset = self.ramdump.field_offset(
+            'struct msm_client_dump', 'end_addr')
+        client_dump_entry_size = self.ramdump.sizeof('struct msm_client_dump')
+
+        mem_dump_data = self.ramdump.addr_lookup('mem_dump_data')
+
+        dump_table = self.ramdump.read_word(
+            mem_dump_data + dump_table_ptr_offset)
+
+        version = self.ramdump.read_word(dump_table + version_offset)
+        num_entries = self.ramdump.read_word(dump_table + num_entries_offset)
+
+        print_out_str('\nDebug image version: {0}.{1} Number of entries {2}'.format(
+            version >> 20, version & 0xFFFFF, num_entries))
+        print_out_str('--------')
+
+        for i in range(0, num_entries):
+            this_client = dump_table + client_entries_offset + \
+                i * client_dump_entry_size
+            client_id = self.ramdump.read_word(this_client + id_offset)
+            client_start = self.ramdump.read_word(
+                this_client + start_addr_offset)
+            client_end = self.ramdump.read_word(this_client + end_addr_offset)
+
+            if client_id < 0 or client_id > len(self.name_lookup_table):
+                print_out_str(
+                    '!!! Invalid client id found {0:x}'.format(client_id))
+                continue
+
+            client_name = self.name_lookup_table[client_id]
+
+            if client_name not in print_table:
+                print_out_str(
+                    '!!! {0} Does not have an associated function. The parser needs to be updated!'.format(client_name))
+            else:
+                print_out_str(
+                    'Parsing debug information for {0}'.format(client_name))
+                func = print_table[client_name]
+                getattr(DebugImage, func)(self, client_start,
+                                          client_end, client_name)
+            print_out_str('--------')
+
+        self.qdss.dump_all(self.ramdump)
diff --git a/linux-ramdump-parser-v2/parsers/dmesg.py b/linux-ramdump-parser-v2/parsers/dmesg.py
new file mode 100644
index 0000000000000000000000000000000000000000..44745549405df9911731f1394af22beab064520e
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/dmesg.py
@@ -0,0 +1,89 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import re
+import string
+
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+
+@register_parser('--dmesg', 'Print the dmesg', shortopt='-d')
+class Dmesg(RamParser):
+
+    def __init__(self, *args):
+        super(Dmesg, self).__init__(*args)
+        self.wrap_cnt = 0
+
+    def cleanupString(self, unclean_str):
+        if unclean_str is None:
+            return str
+        else:
+            return ''.join([c for c in unclean_str if c in string.printable])
+
+    def extract_dmesg_flat(self, ramdump):
+        addr = ramdump.addr_lookup('__log_buf')
+        size = ramdump.sizeof('__log_buf')
+        dmesg = ramdump.read_physical(ramdump.virt_to_phys(addr), size)
+        print_out_str(self.cleanupString(dmesg.decode('ascii', 'ignore')))
+
+    def log_from_idx(self, ramdump, idx, logbuf):
+        len_offset = ramdump.field_offset('struct log', 'len')
+
+        msg = logbuf + idx
+        msg_len = ramdump.read_word(msg + len_offset)
+        if (msg_len == 0):
+            return logbuf
+        else:
+            return msg
+
+    def log_next(self, ramdump, idx, logbuf):
+        len_offset = ramdump.field_offset('struct log', 'len')
+        msg = idx
+
+        msg_len = ramdump.read_halfword(msg + len_offset)
+        if (msg_len == 0):
+            self.wrap_cnt += 1
+            return logbuf
+        else:
+            return idx + msg_len
+
+    def extract_dmesg_binary(self, ramdump):
+        first_idx_addr = ramdump.addr_lookup('log_first_idx')
+        last_idx_addr = ramdump.addr_lookup('log_next_idx')
+        logbuf_addr = ramdump.addr_lookup('__log_buf')
+        time_offset = ramdump.field_offset('struct log', 'ts_nsec')
+        len_offset = ramdump.field_offset('struct log', 'len')
+        text_len_offset = ramdump.field_offset('struct log', 'text_len')
+        log_size = ramdump.sizeof('struct log')
+
+        first_idx = ramdump.read_word(first_idx_addr)
+        last_idx = ramdump.read_word(last_idx_addr)
+
+        curr_idx = logbuf_addr + first_idx
+
+        while curr_idx != logbuf_addr + last_idx and self.wrap_cnt < 2:
+            timestamp = ramdump.read_dword(curr_idx + time_offset)
+            text_len = ramdump.read_halfword(curr_idx + text_len_offset)
+            text_str = ramdump.read_cstring(curr_idx + log_size, text_len)
+            for partial in text_str.split('\n'):
+                f = '[{0:>5}.{1:0>6d}] {2}'.format(
+                    timestamp / 1000000000, (timestamp % 1000000000) / 1000, partial)
+                print_out_str(f)
+            curr_idx = self.log_next(ramdump, curr_idx, logbuf_addr)
+
+    def parse(self):
+        if re.search('3.7.\d', self.ramdump.version) is not None:
+            self.extract_dmesg_binary(self.ramdump)
+        elif re.search('3\.10\.\d', self.ramdump.version) is not None:
+            self.extract_dmesg_binary(self.ramdump)
+        else:
+            self.extract_dmesg_flat(self.ramdump)
diff --git a/linux-ramdump-parser-v2/parsers/gpuinfo.py b/linux-ramdump-parser-v2/parsers/gpuinfo.py
new file mode 100644
index 0000000000000000000000000000000000000000..78a159f63731b6c0fb0d3d2ac4e72771ccfca3ef
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/gpuinfo.py
@@ -0,0 +1,78 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+
+@register_parser('--print-gpuinfo', 'print gpu info like ringbuffer,snapshot and pointer addresses', optional=True)
+class GPUinfo(RamParser):
+
+    def parse(self):
+            if not self.ramdump.is_config_defined('CONFIG_MSM_KGSL'):
+                print_out_str(
+                    'No GPU support detected... Skipping GPUinfo parser.')
+                return
+            adreno_dev_addr = self.ramdump.addr_lookup('device_3d0')
+            kgsl_dev_addr = adreno_dev_addr + self.ramdump.field_offset(
+                'struct adreno_device', 'dev')
+            snapshot = self.ramdump.read_word(kgsl_dev_addr + self.ramdump.field_offset(
+                'struct kgsl_device', 'snapshot'))
+            snapshot_size = self.ramdump.read_word(kgsl_dev_addr +
+                                                   self.ramdump.field_offset(
+                                                       'struct kgsl_device', 'snapshot_size'))
+            snapshot_timestamp = self.ramdump.read_word(kgsl_dev_addr +
+                                                        self.ramdump.field_offset(
+                                                            'struct kgsl_device',
+                                                            'snapshot_timestamp'))
+            ringbuffer_offset = self.ramdump.field_offset(
+                'struct adreno_device', 'ringbuffer')
+            ringbuffer_addr = self.ramdump.read_word(adreno_dev_addr +
+                                                     ringbuffer_offset +
+                                                     self.ramdump.field_offset(
+                                                         'struct adreno_ringbuffer', 'buffer_desc') +
+                                                     self.ramdump.field_offset(
+                                                         'struct kgsl_memdesc', 'physaddr'))
+            memptrs_addr = self.ramdump.read_word(adreno_dev_addr + ringbuffer_offset +
+                                                  self.ramdump.field_offset(
+                                                      'struct adreno_ringbuffer', 'memptrs_desc') +
+                                                  self.ramdump.field_offset(
+                                                      'struct kgsl_memdesc', 'physaddr'))
+            memstore_addr = self.ramdump.read_word(kgsl_dev_addr +
+                                                   self.ramdump.field_offset(
+                                                       'struct kgsl_device', 'memstore') +
+                                                   self.ramdump.field_offset(
+                                                       'struct kgsl_memdesc', 'physaddr'))
+            ringbuffer_size = self.ramdump.read_word(adreno_dev_addr +
+                                                     ringbuffer_offset +
+                                                     self.ramdump.field_offset(
+                                                         'struct adreno_ringbuffer', 'sizedwords'))
+            print_out_str('Ringbuffer address: {0:x}, Ringbuffer sizedwords: '
+                          '{1:x}, Memstore address: {2:x}, Memptrs address: '
+                          '{3:x}'.format(ringbuffer_addr, ringbuffer_size,
+                                         memstore_addr, memptrs_addr))
+            print_out_str('Sanpshot addr: {0:x}, Snapshot size: {1:x}, '
+                          'Snapshot timestamp:{2:x}'.format(snapshot,
+                                                            snapshot_size, snapshot_timestamp))
+            current_context = self.ramdump.read_word(
+                int(memstore_addr) + 32, False)
+            retired_timestamp = self.ramdump.read_word(
+                int(memstore_addr) + 8, False)
+            i = 0
+            for i in range(0, int(ringbuffer_size)):
+                    data = self.ramdump.read_word(
+                        int(ringbuffer_addr) + (i * 4), False)
+                    if int(data) == int(retired_timestamp):
+                            break
+            i = i * 4
+            print_out_str('Current context: {0:x}, Global eoptimestamp: {1:x} '
+                          'found at Ringbuffer[{2:x}]'.format(current_context,
+                                                              retired_timestamp, i))
diff --git a/linux-ramdump-parser-v2/parsers/iommu.py b/linux-ramdump-parser-v2/parsers/iommu.py
new file mode 100644
index 0000000000000000000000000000000000000000..6eb9dacf9f6e2fe84d6c9cae6915def0aeea3f1d
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/iommu.py
@@ -0,0 +1,475 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import math
+
+import rb_tree
+import linux_list as llist
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+IOMMU_DOMAIN_VAR = 'domain_root'
+
+SZ_4K = 0x1000
+SZ_64K = 0x10000
+SZ_1M = 0x100000
+SZ_16M = 0x1000000
+
+MAP_SIZE_STR = ['4K', '8K', '16K', '32K', '64K',
+                '128K', '256K', '512K', '1M', '2M',
+                '4M', '8M', '16M']
+
+
+def get_order(size):
+    order = math.log(size, 2)
+    if (order % 1.0) != 0.0:
+        print 'ERROR: Number is not a power of 2: %x' % (size)
+        order = 0
+    else:
+        order -= math.log(SZ_4K, 2)
+    return int(order)
+
+
+@register_parser('--print-iommu-pg-tables', 'Print IOMMU page tables')
+class IOMMU(RamParser):
+
+    class Domain(object):
+
+        def __init__(self):
+            self.domain_num = -1
+            self.pg_table = 0
+            self.redirect = 0
+            self.ctx_name = ''
+            self.client_name = ''
+
+    class FlatMapping(object):
+
+        def __init__(self, virt, phys=-1, type='[]', size=SZ_4K, mapped=False):
+            self.virt = virt
+            self.phys = phys
+            self.mapping_type = type
+            self.mapping_size = size
+            self.mapped = mapped
+
+    class CollapsedMapping(object):
+
+        def __init__(self, virt_start, virt_end, phys_start=-1, phys_end=-1, type='[]', size=SZ_4K, mapped=False):
+            self.virt_start = virt_start
+            self.virt_end = virt_end - 1
+            self.phys_start = phys_start
+            self.phys_end = phys_end - 1
+            self.mapping_type = type
+            self.mapping_size = size
+            self.mapped = mapped
+
+        def phys_size(self):
+            return (self.phys_end - self.phys_start + 1)
+
+        def virt_size(self):
+            return (self.virt_end - self.virt_start + 1)
+
+    def __init__(self, *args):
+        super(IOMMU, self).__init__(*args)
+        self.out_file = None
+        self.domain_list = []
+        self.NUM_FL_PTE = 4096
+        self.NUM_SL_PTE = 256
+
+        self.FL_BASE_MASK = 0xFFFFFC00
+        self.FL_TYPE_TABLE = (1 << 0)
+        self.FL_TYPE_SECT = (1 << 1)
+        self.FL_SUPERSECTION = (1 << 18)
+        self.FL_AP0 = (1 << 10)
+        self.FL_AP1 = (1 << 11)
+        self.FL_AP2 = (1 << 15)
+        self.FL_SHARED = (1 << 16)
+        self.FL_BUFFERABLE = (1 << 2)
+        self.FL_CACHEABLE = (1 << 3)
+        self.FL_TEX0 = (1 << 12)
+        self.FL_NG = (1 << 17)
+
+        self.SL_BASE_MASK_LARGE = 0xFFFF0000
+        self.SL_BASE_MASK_SMALL = 0xFFFFF000
+        self.SL_TYPE_LARGE = (1 << 0)
+        self.SL_TYPE_SMALL = (2 << 0)
+        self.SL_AP0 = (1 << 4)
+        self.SL_AP1 = (2 << 4)
+        self.SL_AP2 = (1 << 9)
+        self.SL_SHARED = (1 << 10)
+        self.SL_BUFFERABLE = (1 << 2)
+        self.SL_CACHEABLE = (1 << 3)
+        self.SL_TEX0 = (1 << 6)
+        self.SL_NG = (1 << 11)
+        self.ctxdrvdata_name_offset = 0
+        self.ctxdrvdata_num_offset = 0
+        self.ctx_list = []
+
+        self.node_offset = self.ramdump.field_offset(
+            'struct msm_iova_data', 'node')
+        self.domain_num_offset = self.ramdump.field_offset(
+            'struct msm_iova_data', 'domain_num')
+        self.domain_offset = self.ramdump.field_offset(
+            'struct msm_iova_data', 'domain')
+        self.priv_offset = self.ramdump.field_offset(
+            'struct iommu_domain', 'priv')
+        self.ctxdrvdata_attached_offset = self.ramdump.field_offset(
+            'struct msm_iommu_ctx_drvdata', 'attached_elm')
+        self.ctxdrvdata_name_offset = self.ramdump.field_offset(
+            'struct msm_iommu_ctx_drvdata', 'name')
+        self.ctxdrvdata_num_offset = self.ramdump.field_offset(
+            'struct msm_iommu_ctx_drvdata', 'num')
+        self.priv_pt_offset = self.ramdump.field_offset(
+            'struct msm_iommu_priv', 'pt')
+        self.list_attached_offset = self.ramdump.field_offset(
+            'struct msm_iommu_priv', 'list_attached')
+        self.client_name_offset = self.ramdump.field_offset(
+            'struct msm_iommu_priv', 'client_name')
+        self.pgtable_offset = self.ramdump.field_offset(
+            'struct msm_iommu_pt', 'fl_table')
+        self.redirect_offset = self.ramdump.field_offset(
+            'struct msm_iommu_pt', 'redirect')
+
+        self.list_next_offset, self.list_prev_offset = llist.get_list_offsets(
+            self.ramdump)
+
+    def fl_offset(va):
+        return (((va) & 0xFFF00000) >> 20)
+
+    def sl_offset(va):
+        return (((va) & 0xFF000) >> 12)
+
+    def list_func(self, node):
+        ctx_drvdata_name_ptr = self.ramdump.read_word(
+            node + self.ctxdrvdata_name_offset)
+        num = self.ramdump.read_word(node + self.ctxdrvdata_num_offset)
+
+        if ctx_drvdata_name_ptr != 0:
+            name = self.ramdump.read_cstring(ctx_drvdata_name_ptr, 100)
+            self.ctx_list.append((num, name))
+
+    def iommu_domain_func(self, node):
+
+        domain_num_addr = (node - self.node_offset) + self.domain_num_offset
+        domain_num = self.ramdump.read_word(domain_num_addr)
+
+        domain_addr = (node - self.node_offset) + self.domain_offset
+        domain = self.ramdump.read_word(domain_addr)
+
+        priv_ptr = self.ramdump.read_word(domain + self.priv_offset)
+
+        if self.client_name_offset is not None:
+            client_name_ptr = self.ramdump.read_word(
+                priv_ptr + self.client_name_offset)
+            if client_name_ptr != 0:
+                client_name = self.ramdump.read_cstring(client_name_ptr, 100)
+            else:
+                client_name = '(null)'
+        else:
+            client_name = 'unknown'
+
+        if self.list_attached_offset is not None:
+            list_attached = self.ramdump.read_word(
+                priv_ptr + self.list_attached_offset)
+        else:
+            list_attached = None
+
+        if self.priv_pt_offset is not None:
+            pg_table = self.ramdump.read_word(
+                priv_ptr + self.priv_pt_offset + self.pgtable_offset)
+            redirect = self.ramdump.read_word(
+                priv_ptr + self.priv_pt_offset + self.redirect_offset)
+        else:
+            # On some builds we are unable to look up the offsets so hardcode
+            # the offsets.
+            pg_table = self.ramdump.read_word(priv_ptr + 0)
+            redirect = self.ramdump.read_word(priv_ptr + 4)
+
+            # Note: On some code bases we don't have this pg_table and redirect in the priv structure (see msm_iommu_sec.c). It only
+            # contains list_attached. If this is the case we can detect that by checking whether
+            # pg_table == redirect (prev == next pointers of the attached
+            # list).
+            if pg_table == redirect:
+                # This is a secure domain. We don't have access to the page
+                # tables.
+                pg_table = 0
+                redirect = None
+
+        if list_attached is not None and list_attached != 0:
+            list_walker = llist.ListWalker(
+                self.ramdump, list_attached, self.ctxdrvdata_attached_offset, self.list_next_offset, self.list_prev_offset)
+            list_walker.walk(list_attached, self.list_func)
+
+        dom = self.Domain()
+        dom.domain_num = domain_num
+        dom.pg_table = pg_table
+        dom.redirect = redirect
+        dom.ctx_list = self.ctx_list
+        dom.client_name = client_name
+        self.ctx_list = []
+        self.domain_list.append(dom)
+
+    def print_sl_page_table(self, pg_table):
+        sl_pte = pg_table
+        for i in range(0, self.NUM_SL_PTE):
+            phy_addr = self.ramdump.read_word(sl_pte, False)
+            if phy_addr is not None:  # and phy_addr & self.SL_TYPE_SMALL:
+                read_write = '[R/W]'
+                if phy_addr & self.SL_AP2:
+                    read_write = '[R]'
+
+                if phy_addr & self.SL_TYPE_SMALL:
+                    self.out_file.write('SL_PTE[%d] = %x %s\n' %
+                                        (i, phy_addr & self.SL_BASE_MASK_SMALL, read_write))
+                elif phy_addr & self.SL_TYPE_LARGE:
+                    self.out_file.write('SL_PTE[%d] = %x %s\n' %
+                                        (i, phy_addr & self.SL_BASE_MASK_LARGE, read_write))
+                elif phy_addr != 0:
+                    self.out_file.write(
+                        'SL_PTE[%d] = %x NOTE: ERROR [Do not understand page table bits]\n' % (i, phy_addr))
+            sl_pte += 4
+
+    def print_page_table(self, pg_table):
+        fl_pte = pg_table
+        for i in range(0, self.NUM_FL_PTE):
+        # for i in range(0,5):
+            sl_pg_table_phy_addr = self.ramdump.read_word(fl_pte)
+            if sl_pg_table_phy_addr is not None:
+                if sl_pg_table_phy_addr & self.FL_TYPE_TABLE:
+                    self.out_file.write('FL_PTE[%d] = %x [4K/64K]\n' %
+                                        (i, sl_pg_table_phy_addr & self.FL_BASE_MASK))
+                    self.print_sl_page_table(
+                        sl_pg_table_phy_addr & self.FL_BASE_MASK)
+                elif sl_pg_table_phy_addr & self.FL_SUPERSECTION:
+                    self.out_file.write('FL_PTE[%d] = %x [16M]\n' %
+                                        (i, sl_pg_table_phy_addr & 0xFF000000))
+                elif sl_pg_table_phy_addr & self.FL_TYPE_SECT:
+                    self.out_file.write('FL_PTE[%d] = %x [1M]\n' %
+                                        (i, sl_pg_table_phy_addr & 0xFFF00000))
+                elif sl_pg_table_phy_addr != 0:
+                    self.out_file.write(
+                        'FL_PTE[%d] = %x NOTE: ERROR [Cannot understand first level page table entry]\n' % (i, sl_pg_table_phy_addr))
+            else:
+                self.out_file.write(
+                    'FL_PTE[%d] NOTE: ERROR [Cannot understand first level page table entry]\n' % (i))
+            fl_pte += 4
+
+    def get_mapping_info(self, pg_table, index):
+        sl_pte = pg_table + (index * 4)
+        phy_addr = self.ramdump.read_word(sl_pte, False)
+        current_phy_addr = -1
+        current_page_size = SZ_4K
+        current_map_type = 0
+        status = True
+        if phy_addr is not None:
+            if phy_addr & self.SL_AP2:
+                current_map_type = self.SL_AP2
+            if phy_addr & self.SL_TYPE_SMALL:
+                current_phy_addr = phy_addr & self.SL_BASE_MASK_SMALL
+                current_page_size = SZ_4K
+            elif phy_addr & self.SL_TYPE_LARGE:
+                current_phy_addr = phy_addr & self.SL_BASE_MASK_LARGE
+                current_page_size = SZ_64K
+            elif phy_addr != 0:
+                current_phy_addr = phy_addr
+                status = False
+
+        return (current_phy_addr, current_page_size, current_map_type, status)
+
+    def get_sect_mapping_info(self, addr):
+        current_phy_addr = -1
+        current_page_size = SZ_4K
+        current_map_type = 0
+        status = True
+        if addr is not None:
+            if addr & self.SL_AP2:
+                current_map_type = self.SL_AP2
+            if addr & self.FL_SUPERSECTION:
+                current_phy_addr = addr & 0xFF000000
+                current_page_size = SZ_16M
+            elif addr & self.FL_TYPE_SECT:
+                current_phy_addr = addr & 0xFFF00000
+                current_page_size = SZ_1M
+            elif addr != 0:
+                current_phy_addr = addr
+                status = False
+
+        return (current_phy_addr, current_page_size, current_map_type, status)
+
+    def add_flat_mapping(self, mappings, fl_idx, sl_idx, phy_adr, map_type, page_size, mapped):
+        virt = (fl_idx << 20) | (sl_idx << 12)
+        map_type_str = '[R/W]'
+        if map_type == self.SL_AP2:
+            map_type_str = '[R]'
+        map = self.FlatMapping(virt, phy_adr, map_type_str, page_size, mapped)
+        if not mappings.has_key(virt):
+            mappings[virt] = map
+        else:
+            self.out_file.write(
+                '[!] WARNING: FL_PTE[%d] SL_PTE[%d] ERROR [Duplicate mapping?]\n' % (fl_idx, sl_idx))
+        return mappings
+
+    def add_collapsed_mapping(self, mappings, virt_start, virt_end, phys_start, phys_end, map_type, page_size, mapped):
+        map = self.CollapsedMapping(
+            virt_start, virt_end, phys_start, phys_end, map_type, page_size, mapped)
+        if not mappings.has_key(virt_start):
+            mappings[virt_start] = map
+        else:
+            self.out_file.write(
+                '[!] WARNING: ERROR [Duplicate mapping at virtual address 0x%08x?]\n' % (virt_start))
+        return mappings
+
+    def create_flat_mapping(self, pg_table):
+        tmp_mapping = {}
+        fl_pte = pg_table
+        for fl_index in range(0, self.NUM_FL_PTE):
+            fl_pg_table_entry = self.ramdump.read_word(fl_pte)
+
+            if fl_pg_table_entry is not None:
+                if fl_pg_table_entry & self.FL_TYPE_SECT:
+                    (phy_addr, page_size, map_type,
+                     status) = self.get_sect_mapping_info(fl_pg_table_entry)
+                    if status:
+                        if phy_addr != -1:
+                            tmp_mapping = self.add_flat_mapping(
+                                tmp_mapping, fl_index, 0, phy_addr, map_type, page_size, True)
+                        else:
+                            # no mapping
+                            tmp_mapping = self.add_flat_mapping(
+                                tmp_mapping, fl_index, 0, -1, 0, 0, False)
+                elif fl_pg_table_entry & self.FL_TYPE_TABLE:
+                    sl_pte = fl_pg_table_entry & self.FL_BASE_MASK
+
+                    for sl_index in range(0, self.NUM_SL_PTE):
+                        (phy_addr, page_size, map_type,
+                         status) = self.get_mapping_info(sl_pte, sl_index)
+                        if status:
+                            if phy_addr != -1:
+                                tmp_mapping = self.add_flat_mapping(
+                                    tmp_mapping, fl_index, sl_index, phy_addr, map_type, page_size, True)
+                            else:
+                                # no mapping
+                                tmp_mapping = self.add_flat_mapping(
+                                    tmp_mapping, fl_index, sl_index, -1, 0, 0, False)
+                        else:
+                            self.out_file.write(
+                                '[!] WARNING: FL_PTE[%d] SL_PTE[%d] ERROR [Unknown error]\n' % (fl_index, sl_index))
+                elif fl_pg_table_entry != 0:
+                    self.out_file.write(
+                        '[!] WARNING: FL_PTE[%d] = %x NOTE: ERROR [Cannot understand first level page table entry]\n' %
+                        (fl_index, fl_pg_table_entry))
+                else:
+                    tmp_mapping = self.add_flat_mapping(
+                        tmp_mapping, fl_index, 0, -1, 0, 0, False)
+            else:
+                self.out_file.write(
+                    '[!] WARNING: FL_PTE[%d] NOTE: ERROR [Cannot understand first level page table entry]\n' % (fl_index))
+            fl_pte += 4
+        return tmp_mapping
+
+    def create_collapsed_mapping(self, flat_mapping):
+        collapsed_mapping = {}
+        if len(flat_mapping.keys()) > 0:
+            virt_addrs = sorted(flat_mapping.keys())
+            start_map = prev_map = flat_mapping[virt_addrs[0]]
+            last_mapping = False
+            for virt in virt_addrs[1:]:
+                map = flat_mapping[virt]
+                new_mapping = False
+                if map.mapping_size == prev_map.mapping_size and map.mapping_type == prev_map.mapping_type and map.mapped == prev_map.mapped:
+                    if prev_map.mapping_size == SZ_4K:
+                        if (map.phys - SZ_4K) != prev_map.phys and map.phys != prev_map.phys:
+                            new_mapping = True
+                    elif prev_map.mapping_size == SZ_64K:
+                        if (map.phys - SZ_64K) != prev_map.phys and map.phys != prev_map.phys:
+                            new_mapping = True
+                    elif prev_map.mapping_size == SZ_1M:
+                        if (map.phys - SZ_1M) != prev_map.phys and map.phys != prev_map.phys:
+                            new_mapping = True
+                    elif prev_map.mapping_size == SZ_16M:
+                        if (map.phys - SZ_16M) != prev_map.phys and map.phys != prev_map.phys:
+                            new_mapping = True
+                    elif virt == virt_addrs[-1]:
+                        # Last one
+                        last_mapping = True
+                else:
+                    new_mapping = True
+                if new_mapping:
+                    collapsed_mapping = self.add_collapsed_mapping(
+                        collapsed_mapping, start_map.virt, map.virt,
+                        start_map.phys, prev_map.phys +
+                        prev_map.mapping_size,
+                        prev_map.mapping_type, prev_map.mapping_size, prev_map.mapped)
+                    start_map = map
+                elif last_mapping:
+                    collapsed_mapping = self.add_collapsed_mapping(
+                        collapsed_mapping, start_map.virt, 0xFFFFFFFF + 1,
+                        start_map.phys, prev_map.phys +
+                        prev_map.mapping_size,
+                        prev_map.mapping_type, prev_map.mapping_size, prev_map.mapped)
+                prev_map = map
+        return collapsed_mapping
+
+    def print_page_table_pretty(self, pg_table):
+        flat_mapping = self.create_flat_mapping(pg_table)
+        collapsed_mapping = self.create_collapsed_mapping(flat_mapping)
+
+        for virt in sorted(collapsed_mapping.keys()):
+            mapping = collapsed_mapping[virt]
+            if mapping.mapped:
+                self.out_file.write(
+                    '0x%08x--0x%08x [0x%08x] A:0x%08x--0x%08x [0x%08x] %s[%s]\n' % (mapping.virt_start, mapping.virt_end, mapping.virt_size(),
+                                                                                    mapping.phys_start, mapping.phys_end,
+                                                                                    mapping.phys_size(), mapping.mapping_type, MAP_SIZE_STR[get_order(mapping.mapping_size)]))
+            else:
+                self.out_file.write('0x%08x--0x%08x [0x%08x] [UNMAPPED]\n' %
+                                    (mapping.virt_start, mapping.virt_end, mapping.virt_size()))
+
+    def parse(self):
+        iommu_domains_rb_root = self.ramdump.addr_lookup(IOMMU_DOMAIN_VAR)
+        if iommu_domains_rb_root is None:
+            print_out_str(
+                '[!] WARNING: IOMMU domains was not found in this build. No IOMMU page tables will be generated')
+            return
+
+        out_dir = self.ramdump.outdir
+
+        iommu_domains_rb_root_addr = self.ramdump.read_word(
+            iommu_domains_rb_root)
+        rb_walker = rb_tree.RbTreeWalker(self.ramdump)
+        rb_walker.walk(iommu_domains_rb_root_addr, self.iommu_domain_func)
+
+        for d in self.domain_list:
+            self.out_file = self.ramdump.open_file(
+                'msm_iommu_domain_%02d.txt' % (d.domain_num))
+            redirect = 'OFF'
+            if d.redirect is None:
+                redirect = 'UNKNOWN'
+            elif d.redirect > 0:
+                redirect = 'ON'
+            iommu_context = 'None attached'
+            if len(d.ctx_list) > 0:
+                iommu_context = ''
+                for (num, name) in d.ctx_list:
+                    iommu_context += '%s (%d) ' % (name, num)
+            iommu_context = iommu_context.strip()
+
+            self.out_file.write('IOMMU Context: %s. Domain: %s (%d) [L2 cache redirect for page tables is %s]\n' % (
+                iommu_context, d.client_name, d.domain_num, redirect))
+            self.out_file.write(
+                '[VA Start -- VA End  ] [Size      ] [PA Start   -- PA End  ] [Size      ] [Read/Write][Page Table Entry Size]\n')
+            if d.pg_table == 0:
+                self.out_file.write(
+                    'No Page Table Found. (Probably a secure domain)\n')
+            else:
+                self.print_page_table_pretty(d.pg_table)
+                self.out_file.write('\n-------------\nRAW Dump\n')
+                self.print_page_table(d.pg_table)
+            self.out_file.close()
diff --git a/linux-ramdump-parser-v2/parsers/irqstate.py b/linux-ramdump-parser-v2/parsers/irqstate.py
new file mode 100644
index 0000000000000000000000000000000000000000..e5a4bc498898e3c27e552056d67007eba2ccb7b2
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/irqstate.py
@@ -0,0 +1,168 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+
+@register_parser('--print-irqs', 'Print all the irq information', shortopt='-i')
+class IrqParse(RamParser):
+
+    def print_irq_state_3_0(self, ram_dump):
+        print_out_str(
+            '=========================== IRQ STATE ===============================')
+        per_cpu_offset_addr = ram_dump.addr_lookup('__per_cpu_offset')
+        cpu_present_bits_addr = ram_dump.addr_lookup('cpu_present_bits')
+        cpu_present_bits = ram_dump.read_word(cpu_present_bits_addr)
+        cpus = bin(cpu_present_bits).count('1')
+        irq_desc = ram_dump.addr_lookup('irq_desc')
+        foo, irq_desc_size = ram_dump.unwind_lookup(irq_desc, 1)
+        h_irq_offset = ram_dump.field_offset('struct irq_desc', 'handle_irq')
+        irq_num_offset = ram_dump.field_offset('struct irq_data', 'irq')
+        irq_data_offset = ram_dump.field_offset('struct irq_desc', 'irq_data')
+        irq_count_offset = ram_dump.field_offset(
+            'struct irq_desc', 'irq_count')
+        irq_chip_offset = ram_dump.field_offset('struct irq_data', 'chip')
+        irq_action_offset = ram_dump.field_offset('struct irq_desc', 'action')
+        action_name_offset = ram_dump.field_offset('struct irqaction', 'name')
+        kstat_irqs_offset = ram_dump.field_offset(
+            'struct irq_desc', 'kstat_irqs')
+        chip_name_offset = ram_dump.field_offset('struct irq_chip', 'name')
+        irq_desc_entry_size = ram_dump.sizeof('irq_desc[0]')
+        cpu_str = ''
+
+        for i in range(0, cpus):
+            cpu_str = cpu_str + '{0:10} '.format('CPU{0}'.format(i))
+
+        print_out_str(
+            '{0:4} {1} {2:30} {3:10}'.format('IRQ', cpu_str, 'Name', 'Chip'))
+        for i in range(0, irq_desc_size, irq_desc_entry_size):
+            irqnum = ram_dump.read_word(irq_desc + i + irq_num_offset)
+            irqcount = ram_dump.read_word(irq_desc + i + irq_count_offset)
+            action = ram_dump.read_word(irq_desc + i + irq_action_offset)
+            kstat_irqs_addr = ram_dump.read_word(
+                irq_desc + i + kstat_irqs_offset)
+            irq_stats_str = ''
+
+            for j in range(0, cpus):
+                if per_cpu_offset_addr is None:
+                    offset = 0
+                else:
+                    offset = ram_dump.read_word(per_cpu_offset_addr + 4 * j)
+                irq_statsn = ram_dump.read_word(kstat_irqs_addr + offset)
+                irq_stats_str = irq_stats_str + \
+                    '{0:10} '.format('{0}'.format(irq_statsn))
+
+            chip = ram_dump.read_word(
+                irq_desc + i + irq_data_offset + irq_chip_offset)
+            chip_name_addr = ram_dump.read_word(chip + chip_name_offset)
+            chip_name = ram_dump.read_cstring(chip_name_addr, 48)
+
+            if action != 0:
+                name_addr = ram_dump.read_word(action + action_name_offset)
+                name = ram_dump.read_cstring(name_addr, 48)
+                print_out_str(
+                    '{0:4} {1} {2:30} {3:10}'.format(irqnum, irq_stats_str, name, chip_name))
+
+    def radix_tree_lookup_element(self, ram_dump, root_addr, index):
+        rnode_offset = ram_dump.field_offset('struct radix_tree_root', 'rnode')
+        rnode_height_offset = ram_dump.field_offset(
+            'struct radix_tree_node', 'height')
+        slots_offset = ram_dump.field_offset('struct radix_tree_node', 'slots')
+
+        # if CONFIG_BASE_SMALL=0: radix_tree_map_shift = 6
+        radix_tree_map_shift = 6
+        radix_tree_map_mask = 0x3f
+        height_to_maxindex = [0x0, 0x3F, 0x0FFF,
+                              0x0003FFFF, 0x00FFFFFF, 0x3FFFFFFF, 0xFFFFFFFF]
+
+        if ram_dump.read_word(root_addr + rnode_offset) & 1 == 0:
+            if index > 0:
+                return None
+            return (ram_dump.read_word(root_addr + rnode_offset) & 0xfffffffe)
+
+        node_addr = ram_dump.read_word(root_addr + rnode_offset) & 0xfffffffe
+        height = ram_dump.read_word(node_addr + rnode_height_offset)
+
+        if index > height_to_maxindex[height]:
+            return None
+
+        shift = (height - 1) * radix_tree_map_shift
+        for h in range(height, 0, -1):
+            node_addr = ram_dump.read_word(
+                node_addr + slots_offset + ((index >> shift) & radix_tree_map_mask) * 4)
+            if node_addr == 0:
+                return None
+            shift -= radix_tree_map_shift
+        return (node_addr & 0xfffffffe)
+
+    def print_irq_state_sparse_irq(self, ram_dump):
+        h_irq_offset = ram_dump.field_offset('struct irq_desc', 'handle_irq')
+        irq_num_offset = ram_dump.field_offset('struct irq_data', 'irq')
+        irq_data_offset = ram_dump.field_offset('struct irq_desc', 'irq_data')
+        irq_count_offset = ram_dump.field_offset(
+            'struct irq_desc', 'irq_count')
+        irq_chip_offset = ram_dump.field_offset('struct irq_data', 'chip')
+        irq_action_offset = ram_dump.field_offset('struct irq_desc', 'action')
+        action_name_offset = ram_dump.field_offset('struct irqaction', 'name')
+        kstat_irqs_offset = ram_dump.field_offset(
+            'struct irq_desc', 'kstat_irqs')
+        chip_name_offset = ram_dump.field_offset('struct irq_chip', 'name')
+        cpu_str = ''
+
+        irq_desc_tree = ram_dump.addr_lookup('irq_desc_tree')
+        nr_irqs = ram_dump.read_word(ram_dump.addr_lookup('nr_irqs'))
+
+        for i in ram_dump.iter_cpus():
+            cpu_str = cpu_str + '{0:10} '.format('CPU{0}'.format(i))
+
+        print_out_str(
+            '{0:4} {1} {2:30} {3:10}'.format('IRQ', cpu_str, 'Name', 'Chip'))
+        for i in range(0, nr_irqs):
+            irq_desc = self.radix_tree_lookup_element(
+                ram_dump, irq_desc_tree, i)
+            if irq_desc is None:
+                continue
+            irqnum = ram_dump.read_word(irq_desc + irq_num_offset)
+            irqcount = ram_dump.read_word(irq_desc + irq_count_offset)
+            action = ram_dump.read_word(irq_desc + irq_action_offset)
+            kstat_irqs_addr = ram_dump.read_word(irq_desc + kstat_irqs_offset)
+            irq_stats_str = ''
+
+            for j in ram_dump.iter_cpus():
+                irq_statsn = ram_dump.read_word(kstat_irqs_addr, cpu=j)
+                irq_stats_str = irq_stats_str + \
+                    '{0:10} '.format('{0}'.format(irq_statsn))
+
+            chip = ram_dump.read_word(
+                irq_desc + irq_data_offset + irq_chip_offset)
+            chip_name_addr = ram_dump.read_word(chip + chip_name_offset)
+            chip_name = ram_dump.read_cstring(chip_name_addr, 48)
+
+            if action != 0:
+                name_addr = ram_dump.read_word(action + action_name_offset)
+                name = ram_dump.read_cstring(name_addr, 48)
+                print_out_str(
+                    '{0:4} {1} {2:30} {3:10}'.format(irqnum, irq_stats_str, name, chip_name))
+
+    def parse(self):
+        irq_desc = self.ramdump.addr_lookup('irq_desc')
+        if self.ramdump.is_config_defined('CONFIG_SPARSE_IRQ'):
+            self.print_irq_state_sparse_irq(self.ramdump)
+
+        if irq_desc is None:
+            return
+
+        ver = self.ramdump.version
+        if re.search('3.0.\d', ver) is not None:
+            self.print_irq_state_3_0(self.ramdump)
+        if re.search('3.4.\d', ver) is not None:
+            self.print_irq_state_3_0(self.ramdump)
diff --git a/linux-ramdump-parser-v2/parsers/kconfig.py b/linux-ramdump-parser-v2/parsers/kconfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..c586f741cf40b1736f10f5e2e5517c2a6f036a3a
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/kconfig.py
@@ -0,0 +1,26 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from parser_util import register_parser, RamParser
+from print_out import print_out_str
+
+
+@register_parser('--print-kconfig', 'Print saved kernel configuration', shortopt='-c')
+class Kconfig(RamParser):
+
+    def parse(self):
+        saved_config = self.ramdump.open_file('kconfig.txt')
+
+        for l in self.ramdump.config:
+            saved_config.write(l + '\n')
+
+        saved_config.close()
+        print_out_str('---wrote saved kernel config to kconfig.txt')
diff --git a/linux-ramdump-parser-v2/parsers/page_table_dump.py b/linux-ramdump-parser-v2/parsers/page_table_dump.py
new file mode 100644
index 0000000000000000000000000000000000000000..c63c8ca00c0b6d138d1263eb70e1e6389450621b
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/page_table_dump.py
@@ -0,0 +1,22 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from parser_util import register_parser, RamParser
+from print_out import print_out_str
+
+
+@register_parser('--dump-page-tables', 'Dumps page tables')
+class PageTableDump(RamParser):
+
+    def parse(self):
+        with self.ramdump.open_file('page_tables.txt') as f:
+            self.ramdump.mmu.dump_page_tables(f)
+            print_out_str('Page tables dumped to page_tables.txt')
diff --git a/linux-ramdump-parser-v2/parsers/pagetracking.py b/linux-ramdump-parser-v2/parsers/pagetracking.py
new file mode 100644
index 0000000000000000000000000000000000000000..f18a27b066e3a09822c63656868ed0ffe7f5823e
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/pagetracking.py
@@ -0,0 +1,95 @@
+# Copyright (c) 2012, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+
+@register_parser('--print-pagetracking', 'print page tracking information (if available)')
+class PageTracking(RamParser):
+
+    def parse(self):
+        if not self.ramdump.is_config_defined('CONFIG_PAGE_OWNER'):
+            return
+
+        min_pfn_addr = self.ramdump.addr_lookup('min_low_pfn')
+        max_pfn_addr = self.ramdump.addr_lookup('max_pfn')
+        min_pfn = self.ramdump.read_word(
+            min_pfn_addr) + (self.ramdump.phys_offset >> 12)
+        max_pfn = self.ramdump.read_word(
+            max_pfn_addr) + (self.ramdump.phys_offset >> 12)
+
+        order_offset = self.ramdump.field_offset('struct page', 'order')
+        flags_offset = self.ramdump.field_offset('struct page', 'flags')
+        trace_offset = self.ramdump.field_offset('struct page', 'trace')
+        nr_entries_offset = self.ramdump.field_offset(
+            'struct stack_trace', 'nr_entries')
+        trace_entries_offset = self.ramdump.field_offset(
+            'struct page', 'trace_entries')
+
+        out_tracking = self.ramdump.open_file('page_tracking.txt')
+        out_frequency = self.ramdump.open_file('page_frequency.txt')
+        sorted_pages = {}
+
+        print 'min {0:x} max {1:x}'.format(min_pfn, max_pfn)
+
+        for pfn in range(min_pfn, max_pfn):
+            page = pfn_to_page(self.ramdump, pfn)
+
+            # validate this page is free
+            if page_buddy(self.ramdump, page):
+                continue
+
+            nr_trace_entries = self.ramdump.read_word(
+                page + trace_offset + nr_entries_offset)
+
+            if nr_trace_entries <= 0 or nr_trace_entries > 16:
+                continue
+
+            out_tracking.write('PFN 0x{0:x} page 0x{1:x}\n'.format(pfn, page))
+
+            alloc_str = ''
+            for i in range(0, nr_trace_entries):
+                addr = self.ramdump.read_word(
+                    page + trace_entries_offset + i * 4)
+
+                if addr == 0:
+                    break
+                look = self.ramdump.unwind_lookup(addr)
+                if look is None:
+                    break
+                symname, offset = look
+                unwind_dat = '      [<{0:x}>] {1}+0x{2:x}\n'.format(addr,
+                                                                    symname, offset)
+                out_tracking.write(unwind_dat)
+                alloc_str = alloc_str + unwind_dat
+
+            if alloc_str in sorted_pages:
+                sorted_pages[alloc_str] = sorted_pages[alloc_str] + 1
+            else:
+                sorted_pages[alloc_str] = 1
+
+            out_tracking.write('\n')
+
+        sortlist = sorted(sorted_pages.iteritems(),
+                          key=lambda(k, v): (v), reverse=True)
+
+        for k, v in sortlist:
+            out_frequency.write('Allocated {0} times\n'.format(v))
+            out_frequency.write(k)
+            out_frequency.write('\n')
+
+        out_tracking.close()
+        out_frequency.close()
+        print_out_str(
+            '---wrote page tracking information to page_tracking.txt')
+        print_out_str(
+            '---wrote page frequency information to page_frequency.txt')
diff --git a/linux-ramdump-parser-v2/parsers/pagetypeinfo.py b/linux-ramdump-parser-v2/parsers/pagetypeinfo.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a633f0432a938976e18acbb3fd9004ba7be4de0
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/pagetypeinfo.py
@@ -0,0 +1,88 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+
+@register_parser('--print-pagetypeinfo', 'Print the pagetypeinfo')
+class Pagetypeinfo(RamParser):
+
+    def print_pagetype_info_per_zone(self, ramdump, zone, migrate_types):
+
+        free_area_offset = ramdump.field_offset('struct zone', 'free_area')
+        free_area_size = ramdump.sizeof('struct free_area')
+        free_list_offset = ramdump.field_offset(
+            'struct free_area', 'free_list')
+        migratetype_names = ramdump.addr_lookup('migratetype_names')
+        zone_name_offset = ramdump.field_offset('struct zone', 'name')
+        zname_addr = ramdump.read_word(zone + zone_name_offset)
+        zname = ramdump.read_cstring(zname_addr, 12)
+        is_corrupt = False
+        total_bytes = 0
+
+        for mtype in range(0, migrate_types):
+            mname_addr = ramdump.read_word(migratetype_names + mtype * 4)
+            mname = ramdump.read_cstring(mname_addr, 12)
+            pageinfo = ('zone {0:8} type {1:12} '.format(zname, mname))
+            nums = ''
+            total_type_bytes = 0
+            for order in range(0, 11):
+
+                area = zone + free_area_offset + order * free_area_size
+
+                orig_free_list = area + free_list_offset + 8 * mtype
+                curr = orig_free_list
+                pg_count = -1
+                first = True
+                while True:
+                    pg_count = pg_count + 1
+                    next_p = ramdump.read_word(curr)
+                    if next_p == curr:
+                        if not first:
+                            is_corrupt = True
+                        break
+                    first = False
+                    curr = next_p
+                    if curr == orig_free_list:
+                        break
+                nums = nums + ('{0:6}'.format(pg_count))
+                total_type_bytes = total_type_bytes + \
+                    pg_count * 4096 * (2 ** order)
+            print_out_str(pageinfo + nums +
+                          ' = {0} MB'.format(total_type_bytes / (1024 * 1024)))
+            total_bytes = total_bytes + total_type_bytes
+
+        print_out_str('Approximate total for zone {0}: {1} MB\n'.format(
+            zname, total_bytes / (1024 * 1024)))
+        if is_corrupt:
+            print_out_str(
+                '!!! Numbers may not be accurate due to list corruption!')
+
+    def parse(self):
+        migrate_types = self.ramdump.gdbmi.get_value_of('MIGRATE_TYPES')
+        max_nr_zones = self.ramdump.gdbmi.get_value_of('__MAX_NR_ZONES')
+
+        contig_page_data = self.ramdump.addr_lookup('contig_page_data')
+        node_zones_offset = self.ramdump.field_offset(
+            'struct pglist_data', 'node_zones')
+        present_pages_offset = self.ramdump.field_offset(
+            'struct zone', 'present_pages')
+        sizeofzone = self.ramdump.sizeof('struct zone')
+        zone = contig_page_data + node_zones_offset
+
+        while zone < (contig_page_data + node_zones_offset + max_nr_zones * sizeofzone):
+            present_pages = self.ramdump.read_word(zone + present_pages_offset)
+            if not not present_pages:
+                self.print_pagetype_info_per_zone(
+                    self.ramdump, zone, migrate_types)
+
+            zone = zone + sizeofzone
diff --git a/linux-ramdump-parser-v2/parsers/roareadiff.py b/linux-ramdump-parser-v2/parsers/roareadiff.py
new file mode 100644
index 0000000000000000000000000000000000000000..ab0e805b848e90f7d68555b366d9356cee189bed
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/roareadiff.py
@@ -0,0 +1,98 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import struct
+
+from print_out import print_out_str
+from collections import namedtuple
+from parser_util import register_parser, RamParser
+
+ELF32HEADERFORMAT = '<16sHHIIIIIHHHHHH'
+ELF32HEADERSIZE = struct.calcsize(ELF32HEADERFORMAT)
+PRG32HEADERFORMAT = 'IIIIIIII'
+PRG32HEADERSIZE = struct.calcsize(PRG32HEADERFORMAT)
+PF_W = 2
+
+
+@register_parser('--check-rodata', 'check rodata in dump against the static image')
+class ROData(RamParser):
+
+    def parse(self):
+        stext = self.ramdump.addr_lookup('stext')
+        etext = self.ramdump.addr_lookup('_etext')
+
+        with self.ramdump.open_file('roareadiff.txt') as roarea_out:
+
+            fd = open(self.ramdump.vmlinux, 'rb')
+            if not fd:
+                print_out_str('Could not open {0}.'.format(file_path))
+                return
+
+            ElfHeader = namedtuple(
+                'ElfHeader', 'ident type machine version entry phoff shoff flags ehsize phentsize phnum shentsize shnum shstrndx')
+            raw_elfheader = fd.read(ELF32HEADERSIZE)
+            elfheader = ElfHeader._make(
+                struct.unpack(ELF32HEADERFORMAT, raw_elfheader))
+
+            PrgHeader = namedtuple(
+                'Prgheader', 'type offset vaddr paddr filesz memsz flags align')
+            for i in range(elfheader.phnum):
+                fd.seek(elfheader.phoff + i * PRG32HEADERSIZE)
+                raw_prgheader = fd.read(PRG32HEADERSIZE)
+                prgheader = PrgHeader._make(
+                    struct.unpack(PRG32HEADERFORMAT, raw_prgheader))
+
+                if not prgheader.flags & PF_W:
+                    count = prgheader.vaddr
+                    detect = 0
+                    while count < prgheader.vaddr + prgheader.memsz:
+                        fd.seek(prgheader.offset + (count - prgheader.vaddr))
+                        ram_value = self.ramdump.read_word(count)
+                        vm_value = struct.unpack('I', fd.read(4))[0]
+
+                        if detect == 0 and vm_value != ram_value:
+                            print_out_str(
+                                'Differences found! Differences written to roareadiff.txt')
+                            ddr_str = 'detect RO area differences between vmlinux and DDR at 0x{0:0>8x}\n'.format(
+                                count)
+                            ddr_str += 'from DDR:\n'
+                            ddr_str += '{0:0>8x}  *{1:0>8x}'.format(count,
+                                                                    ram_value)
+                            vmlinux_str = 'from vmlinux:\n'
+                            vmlinux_str += '{0:0>8x}  *{1:0>8x}'.format(count,
+                                                                        vm_value)
+                            detect += 1
+                        elif 0 < detect and detect < 64:
+                            if detect % 8 == 0:
+                                ddr_str += '\n{0:0>8x} '.format(count)
+                                vmlinux_str += '\n{0:0>8x} '.format(count)
+                            ddr_str += ' '
+                            vmlinux_str += ' '
+                            if vm_value != ram_value:
+                                ddr_str += '*'
+                                vmlinux_str += '*'
+                            else:
+                                ddr_str += ' '
+                                vmlinux_str += ' '
+                            ddr_str += '{0:0>8x}'.format(ram_value)
+                            vmlinux_str += '{0:0>8x}'.format(vm_value)
+                            detect += 1
+                        elif detect == 64:
+                            ddr_str += '\n\n'
+                            vmlinux_str += '\n\n'
+                            roarea_out.write(ddr_str)
+                            roarea_out.write(vmlinux_str)
+                            detect = 0
+                            continue
+
+                        count += 4
+
+            fd.close()
diff --git a/linux-ramdump-parser-v2/parsers/rtb.py b/linux-ramdump-parser-v2/parsers/rtb.py
new file mode 100644
index 0000000000000000000000000000000000000000..f2517f1bbbc0acdddfb6f9226f5ad54028c8446b
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/rtb.py
@@ -0,0 +1,180 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from tempfile import NamedTemporaryFile
+
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+# struct msm_rtb_layout {
+#        unsigned char sentinel[3];
+#        unsigned char log_type;
+#        void *caller;
+#        unsigned long idx;
+#        void *data;
+#} __attribute__ ((__packed__));
+
+print_table = {
+    'LOGK_NONE': 'print_none',
+    'LOGK_READL': 'print_readlwritel',
+    'LOGK_WRITEL': 'print_readlwritel',
+    'LOGK_LOGBUF': 'print_logbuf',
+    'LOGK_HOTPLUG': 'print_hotplug',
+    'LOGK_CTXID': 'print_ctxid',
+    'LOGK_TIMESTAMP': 'print_timestamp',
+}
+
+
+@register_parser('--print-rtb', 'Print RTB (if enabled)', shortopt='-r')
+class RTB(RamParser):
+
+    def __init__(self, *args):
+        super(RTB, self).__init__(*args)
+        self.name_lookup_table = []
+
+    def get_caller(self, caller):
+        return self.ramdump.gdbmi.get_func_info(caller)
+
+    def get_fun_name(self, addr):
+        l = self.ramdump.unwind_lookup(addr)
+        if l is not None:
+            symname, offset = l
+        else:
+            symname = 'Unknown function'
+        return symname
+
+    def print_none(self, rtbout, rtb_ptr, logtype, data_offset, caller_offset):
+        rtbout.write('{0} No data\n'.format(logtype).encode('ascii', 'ignore'))
+
+    def print_readlwritel(self, rtbout, rtb_ptr, logtype, data_offset, caller_offset):
+        data = self.ramdump.read_word(rtb_ptr + data_offset)
+        caller = self.ramdump.read_word(rtb_ptr + caller_offset)
+        func = self.get_fun_name(caller)
+        line = self.get_caller(caller)
+        rtbout.write('{0} from address {1:x} called from addr {2:x} {3} {4}\n'.format(
+            logtype, data, caller, func, line).encode('ascii', 'ignore'))
+
+    def print_logbuf(self, rtbout, rtb_ptr, logtype, data_offset, caller_offset):
+        data = self.ramdump.read_word(rtb_ptr + data_offset)
+        caller = self.ramdump.read_word(rtb_ptr + caller_offset)
+        func = self.get_fun_name(caller)
+        line = self.get_caller(caller)
+        rtbout.write('{0} log end {1:x} called from addr {2:x} {3} {4}\n'.format(
+            logtype, data, caller, func, line).encode('ascii', 'ignore'))
+
+    def print_hotplug(self, rtbout, rtb_ptr, logtype, data_offset, caller_offset):
+        data = self.ramdump.read_word(rtb_ptr + data_offset)
+        caller = self.ramdump.read_word(rtb_ptr + caller_offset)
+        func = self.get_fun_name(caller)
+        line = self.get_caller(caller)
+        rtbout.write('{0} cpu data {1:x} called from addr {2:x} {3} {4}\n'.format(
+            logtype, data, caller, func, line).encode('ascii', 'ignore'))
+
+    def print_ctxid(self, rtbout, rtb_ptr, logtype, data_offset, caller_offset):
+        data = self.ramdump.read_word(rtb_ptr + data_offset)
+        caller = self.ramdump.read_word(rtb_ptr + caller_offset)
+        func = self.get_fun_name(caller)
+        line = self.get_caller(caller)
+        rtbout.write('{0} context id {1:x} called from addr {2:x} {3} {4}\n'.format(
+            logtype, data, caller, func, line).encode('ascii', 'ignore'))
+
+    def print_timestamp(self, rtbout, rtb_ptr, logtype, data_offset, caller_offset):
+        data = self.ramdump.read_word(rtb_ptr + data_offset)
+        caller = self.ramdump.read_word(rtb_ptr + caller_offset)
+        rtbout.write('{0} Timestamp: {1:x}{2:x}\n'.format(
+            logtype, data, caller).encode('ascii', 'ignore'))
+
+    def parse(self):
+        rtb = self.ramdump.addr_lookup('msm_rtb')
+        if rtb is None:
+            print_out_str(
+                '[!] RTB was not enabled in this build. No RTB files will be generated')
+            return
+        self.name_lookup_table = self.ramdump.gdbmi.get_enum_lookup_table(
+            'logk_event_type', 32)
+        step_size_offset = self.ramdump.field_offset(
+            'struct msm_rtb_state', 'step_size')
+        nentries_offset = self.ramdump.field_offset(
+            'struct msm_rtb_state', 'nentries')
+        rtb_entry_offset = self.ramdump.field_offset(
+            'struct msm_rtb_state', 'rtb')
+        idx_offset = self.ramdump.field_offset('struct msm_rtb_layout', 'idx')
+        caller_offset = self.ramdump.field_offset(
+            'struct msm_rtb_layout', 'caller')
+        log_type_offset = self.ramdump.field_offset(
+            'struct msm_rtb_layout', 'log_type')
+        data_offset = self.ramdump.field_offset(
+            'struct msm_rtb_layout', 'data')
+        rtb_entry_size = self.ramdump.sizeof('struct msm_rtb_layout')
+        step_size = self.ramdump.read_word(rtb + step_size_offset)
+        total_entries = self.ramdump.read_word(rtb + nentries_offset)
+        rtb_read_ptr = self.ramdump.read_word(rtb + rtb_entry_offset)
+        for i in range(0, step_size):
+            rtb_out = self.ramdump.open_file('msm_rtb{0}.txt'.format(i))
+            gdb_cmd = NamedTemporaryFile(mode='w+t', delete=False)
+            gdb_out = NamedTemporaryFile(mode='w+t', delete=False)
+            mask = self.ramdump.read_word(rtb + nentries_offset) - 1
+            if step_size == 1:
+                last = self.ramdump.read_word(
+                    self.ramdump.addr_lookup('msm_rtb_idx'))
+            else:
+                last = self.ramdump.read_word(self.ramdump.addr_lookup(
+                    'msm_rtb_idx_cpu') + self.ramdump.read_word(self.ramdump.addr_lookup('__per_cpu_offset') + 4 * i))
+            last = last & mask
+            last_ptr = 0
+            next_ptr = 0
+            next_entry = 0
+            while True:
+                next_entry = (last + step_size) & mask
+                last_ptr = rtb_read_ptr + last * rtb_entry_size + idx_offset
+                next_ptr = rtb_read_ptr + next_entry * \
+                    rtb_entry_size + idx_offset
+                a = self.ramdump.read_word(last_ptr)
+                b = self.ramdump.read_word(next_ptr)
+                if a < b:
+                    last = next_entry
+                if next_entry != last:
+                    break
+            stop = 0
+            rtb_logtype_offset = self.ramdump.field_offset(
+                'struct msm_rtb_layout', 'log_type')
+            rtb_idx_offset = self.ramdump.field_offset(
+                'struct msm_rtb_layout', 'idx')
+            rtb_data_offset = self.ramdump.field_offset(
+                'struct msm_rtb_layout', 'data')
+            rtb_caller_offset = self.ramdump.field_offset(
+                'struct msm_rtb_layout', 'caller')
+            while True:
+                ptr = rtb_read_ptr + next_entry * rtb_entry_size
+                stamp = self.ramdump.read_word(ptr + rtb_idx_offset)
+                rtb_out.write('{0:x} '.format(stamp).encode('ascii', 'ignore'))
+                item = self.ramdump.read_byte(ptr + rtb_logtype_offset)
+                item = item & 0x7F
+                name_str = '(unknown)'
+                if item >= len(self.name_lookup_table) or item < 0:
+                    self.print_none(rtb_out, ptr, name_str,
+                                    rtb_data_offset, rtb_caller_offset)
+                else:
+                    name_str = self.name_lookup_table[item]
+                    if name_str not in print_table:
+                        self.print_none(rtb_out, ptr, name_str,
+                                        rtb_data_offset, rtb_caller_offset)
+                    else:
+                        func = print_table[name_str]
+                        getattr(RTB, func)(self, rtb_out, ptr, name_str,
+                                           rtb_data_offset, rtb_caller_offset)
+                if next_entry == last:
+                    stop = 1
+                next_entry = (next_entry + step_size) & mask
+                if (stop == 1):
+                    break
+            print_out_str('Wrote RTB to msm_rtb{0}.txt'.format(i))
+            rtb_out.close()
diff --git a/linux-ramdump-parser-v2/parsers/runqueue.py b/linux-ramdump-parser-v2/parsers/runqueue.py
new file mode 100644
index 0000000000000000000000000000000000000000..64cd82d7b589fed9b2ece83fa2e1f46e7ceec2c7
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/runqueue.py
@@ -0,0 +1,205 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import rb_tree
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+
+@register_parser('--print-runqueues', 'Print the runqueue status')
+class RunQueues(RamParser):
+
+    def __init__(self, *args):
+        super(RunQueues, self).__init__(*args)
+        self.domain_list = []
+        self.tab_offset = 0
+
+    def ffs(self, num):
+        # Check there is at least one bit set.
+        if num == 0:
+            return None
+        # Right-shift until we have the first set bit in the LSB position.
+        i = 0
+        while (num % 2) == 0:
+            i += 1
+            num = num >> 1
+        return i
+
+    def print_out_str_with_tab(self, string):
+        string = self.tab_offset * ' |  ' + ' |--' + string
+        print_out_str(string)
+
+    def print_task_state(self, status, task_addr):
+        pid_offset = self.ramdump.field_offset('struct task_struct', 'pid')
+        comm_offset = self.ramdump.field_offset('struct task_struct', 'comm')
+
+        if 0 < task_addr:
+            pid = self.ramdump.read_word(task_addr + pid_offset)
+            taskname = self.ramdump.read_cstring(task_addr + comm_offset, 16)
+            self.print_out_str_with_tab(
+                '{0}: {1}({2})'.format(status, taskname, pid))
+        else:
+            self.print_out_str_with_tab('{0}: None(0)'.format(status))
+
+    def print_cgroup_state(self, status, se_addr):
+        se_offset = self.ramdump.field_offset('struct task_struct', 'se')
+        cfs_nr_running_offset = self.ramdump.field_offset(
+            'struct cfs_rq', 'nr_running')
+        my_q_offset = self.ramdump.field_offset('struct sched_entity', 'my_q')
+
+        if se_addr == 0:
+            self.print_task_state(status, se_addr)
+        else:
+            my_q_addr = self.ramdump.read_word(se_addr + my_q_offset)
+            if my_q_addr == 0:
+                self.print_task_state(status, se_addr - se_offset)
+            else:
+                cfs_nr_running = self.ramdump.read_word(
+                    my_q_addr + cfs_nr_running_offset)
+                self.print_out_str_with_tab(
+                    '{0}: {1} process is grouping'.format(status, cfs_nr_running))
+                self.tab_offset += 1
+                self.print_cfs_state(my_q_addr)
+                self.tab_offset -= 1
+
+    def cfs_node_func(self, node):
+        run_node_offset = self.ramdump.field_offset(
+            'struct sched_entity', 'run_node')
+
+        task_se = node - run_node_offset
+        self.print_cgroup_state('pend', task_se)
+
+    def print_cfs_state(self, cfs_rq_addr):
+        tasks_timeline_offset = self.ramdump.field_offset(
+            'struct cfs_rq', 'tasks_timeline')
+        curr_offset = self.ramdump.field_offset('struct cfs_rq', 'curr')
+        next_offset = self.ramdump.field_offset('struct cfs_rq', 'next')
+        last_offset = self.ramdump.field_offset('struct cfs_rq', 'last')
+        skip_offset = self.ramdump.field_offset('struct cfs_rq', 'skip')
+
+        tasks_timeline_addr = self.ramdump.read_word(
+            cfs_rq_addr + tasks_timeline_offset)
+
+        curr_se = self.ramdump.read_word(cfs_rq_addr + curr_offset)
+        self.print_cgroup_state('curr', curr_se)
+        next_se = self.ramdump.read_word(cfs_rq_addr + next_offset)
+        self.print_cgroup_state('next', next_se)
+        last_se = self.ramdump.read_word(cfs_rq_addr + last_offset)
+        self.print_cgroup_state('last', last_se)
+        skip_se = self.ramdump.read_word(cfs_rq_addr + skip_offset)
+        self.print_cgroup_state('skip', skip_se)
+
+        rb_walker = rb_tree.RbTreeWalker(self.ramdump)
+        rb_walker.walk(tasks_timeline_addr, self.cfs_node_func)
+
+    def print_rt_cgroup_state(self, status, rt_addr):
+        rt_offset = self.ramdump.field_offset('struct task_struct', 'rt')
+        rt_nr_running_offset = self.ramdump.field_offset(
+            'struct rt_rq', 'nr_running')
+        my_q_offset = self.ramdump.field_offset(
+            'struct sched_rt_entity', 'my_q')
+
+        if rt_addr == 0:
+            self.print_task_state(status, se_addr)
+        else:
+            my_q_addr = self.ramdump.read_word(rt_addr + my_q_offset)
+            if my_q_addr == 0:
+                self.print_task_state(status, rt_addr - rt_offset)
+            else:
+                rt_nr_running = self.ramdump.read_word(
+                    my_q_addr + rt_nr_running_offset)
+                self.print_out_str_with_tab(
+                    '{0}: {1} process is grouping'.format(status, rt_nr_running))
+                self.tab_offset += 1
+                self.print_rt_state(my_q_addr)
+                self.tab_offset -= 1
+
+    def print_rt_state(self, rt_rq_addr):
+        active_offset = self.ramdump.field_offset('struct rt_rq', 'active')
+        queue_offset = self.ramdump.field_offset(
+            'struct rt_prio_array', 'queue')
+        rt_offset = self.ramdump.field_offset('struct task_struct', 'rt')
+
+        array_addr = rt_rq_addr + active_offset
+
+        for i in range(0, 4):
+            bitmap = self.ramdump.read_word(array_addr + i * 4)
+            while True:
+                idx = self.ffs(bitmap)
+                if idx is not None and idx + i * 32 < 100:
+                    bitmap &= ~(1 << idx)
+                    idx = (idx + i * 32) * 4 * 2
+                    queue_addr = self.ramdump.read_word(
+                        array_addr + queue_offset + idx)
+                    while queue_addr != array_addr + queue_offset + idx:
+                        task_addr = queue_addr - rt_offset
+                        self.print_task_state('pend', task_addr)
+                        queue_addr = self.ramdump.read_word(queue_addr)
+                else:
+                    break
+
+    def print_latest_callstack_maybe(self, task_addr):
+        text_start_addr = self.ramdump.addr_lookup('_text')
+        text_end_addr = self.ramdump.addr_lookup('_etext')
+        stack_offset = self.ramdump.field_offset('struct task_struct', 'stack')
+
+        stack_addr = self.ramdump.read_word(task_addr + stack_offset)
+        print_out_str('current callstack is maybe:')
+
+        for i in range(stack_addr, stack_addr + 0x2000, 4):
+            callstack_addr = self.ramdump.read_word(i)
+            if text_start_addr <= callstack_addr and callstack_addr < text_end_addr:
+                wname = self.ramdump.unwind_lookup(callstack_addr)
+                if wname is not None:
+                    print_out_str('0x{0:x}:{1}'.format(i, wname))
+
+    def parse(self):
+        print_out_str(
+            '======================= RUNQUEUE STATE ============================')
+        runqueues_addr = self.ramdump.addr_lookup('runqueues')
+        nr_running_offset = self.ramdump.field_offset(
+            'struct rq', 'nr_running')
+        curr_offset = self.ramdump.field_offset('struct rq', 'curr')
+        idle_offset = self.ramdump.field_offset('struct rq', 'idle')
+        stop_offset = self.ramdump.field_offset('struct rq', 'stop')
+        cfs_rq_offset = self.ramdump.field_offset('struct rq', 'cfs')
+        rt_rq_offset = self.ramdump.field_offset('struct rq', 'rt')
+        cfs_nr_running_offset = self.ramdump.field_offset(
+            'struct cfs_rq', 'nr_running')
+        rt_nr_running_offset = self.ramdump.field_offset(
+            'struct rt_rq', 'rt_nr_running')
+
+        for i in self.ramdump.iter_cpus():
+            rq_addr = runqueues_addr + self.ramdump.per_cpu_offset(i)
+            nr_running = self.ramdump.read_word(rq_addr + nr_running_offset)
+            print_out_str(
+                'CPU{0} {1} process is running'.format(i, nr_running))
+            curr_addr = self.ramdump.read_word(rq_addr + curr_offset)
+            self.print_task_state('curr', curr_addr)
+            idle_addr = self.ramdump.read_word(rq_addr + idle_offset)
+            self.print_task_state('idle', idle_addr)
+            stop_addr = self.ramdump.read_word(rq_addr + stop_offset)
+            self.print_task_state('stop', stop_addr)
+
+            cfs_rq_addr = rq_addr + cfs_rq_offset
+            cfs_nr_running = self.ramdump.read_word(
+                cfs_rq_addr + cfs_nr_running_offset)
+            print_out_str('CFS {0} process is pending'.format(cfs_nr_running))
+            self.print_cfs_state(cfs_rq_addr)
+
+            rt_rq_addr = rq_addr + rt_rq_offset
+            rt_nr_running = self.ramdump.read_word(
+                rt_rq_addr + rt_nr_running_offset)
+            print_out_str('RT {0} process is pending'.format(rt_nr_running))
+            self.print_rt_state(rt_rq_addr)
+
+            self.print_latest_callstack_maybe(curr_addr)
+            print_out_str('')
diff --git a/linux-ramdump-parser-v2/parsers/slabinfo.py b/linux-ramdump-parser-v2/parsers/slabinfo.py
new file mode 100644
index 0000000000000000000000000000000000000000..40d7f2249fb5cbb61d1d35969e866e26b5d1eff6
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/slabinfo.py
@@ -0,0 +1,213 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import re
+
+from mm import page_address
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+
+@register_parser('--slabinfo', 'print information about slabs', optional=True)
+class Slabinfo(RamParser):
+
+    def get_free_pointer(self, ramdump, s, obj):
+        # just like validate_slab_slab!
+        slab_offset_offset = self.ramdump.field_offset(
+            'struct kmem_cache', 'offset')
+        slab_offset = self.ramdump.read_word(s + slab_offset_offset)
+        return self.ramdump.read_word(obj + slab_offset)
+
+    def slab_index(self, ramdump, p, addr, slab):
+        slab_size_offset = self.ramdump.field_offset(
+            'struct kmem_cache', 'size')
+        slab_size = self.ramdump.read_word(slab + slab_size_offset)
+        if slab_size is None:
+            return -1
+        return (p - addr) / slab_size
+
+    def get_map(self, ramdump, slab, page, bitarray):
+        freelist_offset = self.ramdump.field_offset('struct page', 'freelist')
+        freelist = self.ramdump.read_word(page + freelist_offset)
+        p = freelist
+        addr = page_address(self.ramdump, page)
+        if addr is None:
+            return
+        while p != 0 and p is not None:
+            idx = self.slab_index(self.ramdump, p, addr, slab)
+            if idx >= len(bitarray) or idx < 0:
+                return
+            bitarray[idx] = 1
+            p = self.get_free_pointer(self.ramdump, slab, p)
+
+    def get_track(self, ramdump, slab, obj, track_type):
+        track_size = self.ramdump.sizeof('struct track')
+        slab_offset_offset = self.ramdump.field_offset(
+            'struct kmem_cache', 'offset')
+        slab_inuse_offset = self.ramdump.field_offset(
+            'struct kmem_cache', 'inuse')
+        slab_offset = self.ramdump.read_word(slab + slab_offset_offset)
+        slab_inuse = self.ramdump.read_word(slab + slab_inuse_offset)
+        if slab_offset != 0:
+            p = obj + slab_offset + 4
+        else:
+            p = obj + slab_inuse
+        return p + track_type * track_size
+
+    def print_track(self, ramdump, slab, obj, track_type, out_file):
+        p = self.get_track(self.ramdump, slab, obj, track_type)
+        track_addrs_offset = self.ramdump.field_offset('struct track', 'addrs')
+        start = p + track_addrs_offset
+        if track_type == 0:
+            out_file.write('   ALLOC STACK\n')
+        else:
+            out_file.write('   FREE STACK\n')
+        for i in range(0, 16):
+            a = self.ramdump.read_word(start + 4 * i)
+            if a == 0:
+                break
+            look = self.ramdump.unwind_lookup(a)
+            if look is None:
+                return
+            symname, offset = look
+            out_file.write(
+                '      [<{0:x}>] {1}+0x{2:x}\n'.format(a, symname, offset))
+        out_file.write('\n')
+
+    def get_nobjects(self, ramdump, page):
+        if re.search('3\.0\.\d', self.ramdump.version) is not None:
+            n_objects_offset = self.ramdump.field_offset(
+                'struct page', 'objects')
+            n_objects = self.ramdump.read_halfword(page + n_objects_offset)
+            return n_objects
+        else:
+            # The objects field is now a bit field. This confuses GDB as it thinks the
+            # offset is always 0. Work around this for now
+            map_count_offset = self.ramdump.field_offset(
+                'struct page', '_mapcount')
+            count = self.ramdump.read_word(page + map_count_offset)
+            if count is None:
+                return None
+            n_objects = (count >> 16) & 0xFFFF
+            return n_objects
+
+    def print_slab(self, ramdump, slab_start, slab, page, out_file):
+        p = slab_start
+        if page is None:
+            return
+        n_objects = self.get_nobjects(self.ramdump, page)
+        if n_objects is None:
+            return
+        slab_size_offset = self.ramdump.field_offset(
+            'struct kmem_cache', 'size')
+        slab_size = self.ramdump.read_word(slab + slab_size_offset)
+        if slab_size is None:
+            return
+        slab_max_offset = self.ramdump.field_offset('struct kmem_cache', 'max')
+        slab_max = self.ramdump.read_word(slab + slab_max_offset)
+        if slab_max is None:
+            return
+        bitarray = [0] * slab_max
+        addr = page_address(self.ramdump, page)
+        self.get_map(self.ramdump, slab, page, bitarray)
+        while p < slab_start + n_objects * slab_size:
+            idx = self.slab_index(self.ramdump, p, addr, slab)
+            bitidx = self.slab_index(self.ramdump, p, addr, slab)
+            if bitidx >= len(bitarray) or bitidx < 0:
+                return
+            if bitarray[bitidx] == 1:
+                out_file.write(
+                    '   Object {0:x}-{1:x} FREE\n'.format(p, p + slab_size))
+            else:
+                out_file.write(
+                    '   Object {0:x}-{1:x} ALLOCATED\n'.format(p, p + slab_size))
+            if self.ramdump.is_config_defined('CONFIG_SLUB_DEBUG_ON'):
+                self.print_track(self.ramdump, slab, p, 0, out_file)
+                self.print_track(self.ramdump, slab, p, 1, out_file)
+            p = p + slab_size
+
+    def print_slab_page_info(self, ramdump, slab, slab_node, start, out_file):
+        page = self.ramdump.read_word(start)
+        if page == 0:
+            return
+        slab_lru_offset = self.ramdump.field_offset('struct page', 'lru')
+        page_flags_offset = self.ramdump.field_offset('struct page', 'flags')
+        slab_node_offset = self.ramdump.field_offset(
+            'struct kmem_cache', 'size')
+        while page != start:
+            if page is None:
+                return
+            page = page - slab_lru_offset
+            page_flags = self.ramdump.read_word(page + page_flags_offset)
+            page_addr = page_address(self.ramdump, page)
+            self.print_slab(self.ramdump, page_addr, slab, page, out_file)
+            page = self.ramdump.read_word(page + slab_lru_offset)
+
+    def print_per_cpu_slab_info(self, ramdump, slab, slab_node, start, out_file):
+        page = self.ramdump.read_word(start)
+        if page == 0:
+            return
+        page_flags_offset = self.ramdump.field_offset('struct page', 'flags')
+        if page is None:
+            return
+        page_flags = self.ramdump.read_word(page + page_flags_offset)
+        page_addr = page_address(self.ramdump, page)
+        self.print_slab(self.ramdump, page_addr, slab, page, out_file)
+
+    # based on validate_slab_cache. Currently assuming there is only one numa node
+    # in the system because the code to do that correctly is a big pain. This will
+    # need to be changed if we ever do NUMA properly.
+    def parse(self):
+        slab_out = self.ramdump.open_file('slabs.txt')
+        original_slab = self.ramdump.addr_lookup('slab_caches')
+        per_cpu_offset = self.ramdump.addr_lookup('__per_cpu_offset')
+        cpu_present_bits_addr = self.ramdump.addr_lookup('cpu_present_bits')
+        cpu_present_bits = self.ramdump.read_word(cpu_present_bits_addr)
+        cpus = bin(cpu_present_bits).count('1')
+        slab_list_offset = self.ramdump.field_offset(
+            'struct kmem_cache', 'list')
+        slab_name_offset = self.ramdump.field_offset(
+            'struct kmem_cache', 'name')
+        slab_node_offset = self.ramdump.field_offset(
+            'struct kmem_cache', 'node')
+        cpu_cache_page_offset = self.ramdump.field_offset(
+            'struct kmem_cache_cpu', 'page')
+        cpu_slab_offset = self.ramdump.field_offset(
+            'struct kmem_cache', 'cpu_slab')
+        slab_partial_offset = self.ramdump.field_offset(
+            'struct kmem_cache_node', 'partial')
+        slab_full_offset = self.ramdump.field_offset(
+            'struct kmem_cache_node', 'full')
+        slab = self.ramdump.read_word(original_slab)
+        while slab != original_slab:
+            slab = slab - slab_list_offset
+            slab_name_addr = self.ramdump.read_word(slab + slab_name_offset)
+            # actually an array but again, no numa
+            slab_node_addr = self.ramdump.read_word(slab + slab_node_offset)
+            slab_node = self.ramdump.read_word(slab_node_addr)
+            slab_name = self.ramdump.read_cstring(slab_name_addr, 48)
+            cpu_slab_addr = self.ramdump.read_word(slab + cpu_slab_offset)
+            print_out_str('Parsing slab {0}'.format(slab_name))
+            slab_out.write(
+                '{0:x} slab {1} {2:x}\n'.format(slab, slab_name, slab_node_addr))
+            self.print_slab_page_info(
+                self.ramdump, slab, slab_node, slab_node_addr + slab_partial_offset, slab_out)
+            self.print_slab_page_info(
+                self.ramdump, slab, slab_node, slab_node_addr + slab_full_offset, slab_out)
+
+            for i in range(0, cpus):
+                cpu_slabn_addr = cpu_slab_addr + \
+                    self.ramdump.read_word(per_cpu_offset + 4 * i)
+                self.print_per_cpu_slab_info(
+                    self.ramdump, slab, slab_node, cpu_slabn_addr + cpu_cache_page_offset, slab_out)
+
+            slab = self.ramdump.read_word(slab + slab_list_offset)
+        print_out_str('---wrote slab information to slabs.txt')
diff --git a/linux-ramdump-parser-v2/parsers/taskdump.py b/linux-ramdump-parser-v2/parsers/taskdump.py
new file mode 100644
index 0000000000000000000000000000000000000000..7de493c346180715f829a1c7576c76a8298066f2
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/taskdump.py
@@ -0,0 +1,217 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import string
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+
+def cleanupString(str):
+    if str is None:
+        return str
+    else:
+        return ''.join([c for c in str if c in string.printable])
+
+cpu_context_save_str = ''.join([
+    'I',  # __u32   r4
+    'I',  # __u32   r5
+    'I',  # __u32   r6
+    'I',  # __u32   r7
+    'I',  # __u32   r8
+    'I',  # __u32   r9
+    'I',  # __u32   sl
+    'I',  # __u32   fp 14
+    'I',  # __u32   sp 15
+    'I',  # __u32   pc 16
+    'II',  # __u32   extra[2]               /* Xscale 'acc' register, etc */
+])
+
+thread_info_str = ''.join([  # struct thread_info {
+    'I',  # flags          /* low level flags */
+    # int                     preempt_count  /* 0 => preemptable, <0 => bug */
+    'I',
+    'I',  # addr_limit     /* address limit */
+    'I',  # task
+    'I',  # exec_domain   /* execution domain */
+    'I',  # 5                 cpu            /* cpu */
+    'I',  # cpu_domain     /* cpu domain */
+    # struct cpu_context_save cpu_context    /* cpu context */
+    cpu_context_save_str,
+    'I',  # syscall        /* syscall number */
+    # unsigned char                    used_cp[16]    /* thread used copro */
+    'I',
+    'I',  # tp_value
+])
+
+thread_info_cpu_idx = 5
+thread_info_fp_idx = 14
+thread_info_sp_idx = 15
+thread_info_pc_idx = 16
+
+
+def find_panic(ramdump, addr_stack, thread_task_name):
+    for i in range(addr_stack, addr_stack + 0x2000, 4):
+        pc = ramdump.read_word(i)
+        lr = ramdump.read_word(i + 4)
+        spx = ramdump.read_word(i + 8)
+        l = ramdump.unwind_lookup(pc)
+        if l is not None:
+            s, offset = l
+            if s == 'panic':
+                print_out_str('Faulting process found! Name {0}. Attempting to retrieve stack (sp = {1:x} pc = {2:x})'.format(
+                    thread_task_name, i + 4, pc))
+                ramdump.unwind.unwind_backtrace(i + 4, 0, pc, lr, '')
+                regspanic = ramdump.open_file('regs_panic.cmm')
+                regspanic.write('r.s pc 0x{0:x}\n'.format(pc))
+                regspanic.write('r.s r13 0x{0:x}\n'.format(i + 4))
+                regspanic.close()
+                return True
+    return False
+
+
+def dump_thread_group(ramdump, thread_group, task_out, check_for_panic=0):
+    offset_thread_group = ramdump.field_offset(
+        'struct task_struct', 'thread_group')
+    offset_comm = ramdump.field_offset('struct task_struct', 'comm')
+    offset_pid = ramdump.field_offset('struct task_struct', 'pid')
+    offset_stack = ramdump.field_offset('struct task_struct', 'stack')
+    offset_state = ramdump.field_offset('struct task_struct', 'state')
+    offset_exit_state = ramdump.field_offset(
+        'struct task_struct', 'exit_state')
+    orig_thread_group = thread_group
+    first = 0
+    seen_threads = []
+    while True:
+        next_thread_start = thread_group - offset_thread_group
+        next_thread_comm = next_thread_start + offset_comm
+        next_thread_pid = next_thread_start + offset_pid
+        next_thread_stack = next_thread_start + offset_stack
+        next_thread_state = next_thread_start + offset_state
+        next_thread_exit_state = next_thread_start + offset_exit_state
+        thread_task_name = cleanupString(
+            ramdump.read_cstring(next_thread_comm, 16))
+        if thread_task_name is None:
+            return
+        thread_task_pid = ramdump.read_word(next_thread_pid)
+        if thread_task_pid is None:
+            return
+        task_state = ramdump.read_word(next_thread_state)
+        if task_state is None:
+            return
+        task_exit_state = ramdump.read_word(next_thread_exit_state)
+        if task_exit_state is None:
+            return
+        addr_stack = ramdump.read_word(next_thread_stack)
+        if addr_stack is None:
+            return
+        threadinfo = ramdump.read_string(addr_stack, thread_info_str)
+        if threadinfo is None:
+            return
+        if not check_for_panic:
+            if not first:
+                task_out.write('Process: {0}, cpu: {1} pid: {2} start: 0x{3:x}\n'.format(
+                    thread_task_name, threadinfo[thread_info_cpu_idx], thread_task_pid, next_thread_start))
+                task_out.write(
+                    '=====================================================\n')
+                first = 1
+            task_out.write('    Task name: {0} pid: {1} cpu: {2}\n    state: 0x{3:x} exit_state: 0x{4:x} stack base: 0x{5:x}\n'.format(
+                thread_task_name, thread_task_pid, threadinfo[thread_info_cpu_idx], task_state, task_exit_state, addr_stack))
+            task_out.write('    Stack:')
+            ramdump.unwind.unwind_backtrace(threadinfo[thread_info_sp_idx], threadinfo[
+                                            thread_info_fp_idx], threadinfo[thread_info_pc_idx], 0, '    ', task_out)
+            task_out.write(
+                '=======================================================\n')
+        else:
+            find_panic(ramdump, addr_stack, thread_task_name)
+
+        next_thr = ramdump.read_word(thread_group)
+        if (next_thr == thread_group) and (next_thr != orig_thread_group):
+            if not check_for_panic:
+                task_out.write(
+                    '!!!! Cycle in thread group! The list is corrupt!\n')
+            break
+        if (next_thr in seen_threads):
+            break
+
+        seen_threads.append(next_thr)
+        thread_group = next_thr
+        if thread_group == orig_thread_group:
+            break
+
+
+def do_dump_stacks(ramdump, check_for_panic=0):
+    offset_tasks = ramdump.field_offset('struct task_struct', 'tasks')
+    offset_comm = ramdump.field_offset('struct task_struct', 'comm')
+    offset_stack = ramdump.field_offset('struct task_struct', 'stack')
+    offset_thread_group = ramdump.field_offset(
+        'struct task_struct', 'thread_group')
+    offset_pid = ramdump.field_offset('struct task_struct', 'pid')
+    offset_state = ramdump.field_offset('struct task_struct', 'state')
+    offset_exit_state = ramdump.field_offset(
+        'struct task_struct', 'exit_state')
+    init_addr = ramdump.addr_lookup('init_task')
+    init_next_task = init_addr + offset_tasks
+    orig_init_next_task = init_next_task
+    init_thread_group = init_addr + offset_thread_group
+    seen_tasks = []
+    if check_for_panic == 0:
+        task_out = ramdump.open_file('tasks.txt')
+    else:
+        task_out = None
+    while True:
+        dump_thread_group(ramdump, init_thread_group,
+                          task_out, check_for_panic)
+        next_task = ramdump.read_word(init_next_task)
+        if next_task is None:
+            return
+
+        if (next_task == init_next_task) and (next_task != orig_init_next_task):
+            if not check_for_panic:
+                task_out.write(
+                    '!!!! Cycle in task list! The list is corrupt!\n')
+            break
+
+        if (next_task in seen_tasks):
+            break
+
+        seen_tasks.append(next_task)
+
+        init_next_task = next_task
+        init_thread_group = init_next_task - offset_tasks + offset_thread_group
+        if init_next_task == orig_init_next_task:
+            break
+    if check_for_panic == 0:
+        task_out.close()
+        print_out_str('---wrote tasks to tasks.txt')
+
+
+@register_parser('--print-tasks', 'Print all the task information', shortopt='-t')
+class DumpTasks(RamParser):
+
+    def parse(self):
+        do_dump_stacks(self.ramdump, 0)
+
+
+@register_parser('--check-for-panic', 'Check if a kernel panic occured', shortopt='-p')
+class CheckForPanic(RamParser):
+
+    def parse(self):
+        addr = self.ramdump.addr_lookup('in_panic')
+
+        result = self.ramdump.read_word(addr)
+
+        if result == 1:
+            print_out_str('-------------------------------------------------')
+            print_out_str('[!] KERNEL PANIC detected!')
+            print_out_str('-------------------------------------------------')
+            do_dump_stacks(self.ramdump, 1)
+        else:
+            print_out_str('No kernel panic detected')
diff --git a/linux-ramdump-parser-v2/parsers/vmalloc.py b/linux-ramdump-parser-v2/parsers/vmalloc.py
new file mode 100644
index 0000000000000000000000000000000000000000..832c6e6f114bfd9337ea8debb0fee621b6d531f8
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/vmalloc.py
@@ -0,0 +1,91 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+VM_IOREMAP = 0x00000001
+VM_ALLOC = 0x00000002
+VM_MAP = 0x00000004
+VM_USERMAP = 0x00000008
+VM_VPAGES = 0x00000010
+VM_UNLIST = 0x00000020
+
+
+@register_parser('--print-vmalloc', 'print vmalloc information')
+class Vmalloc(RamParser):
+
+    def print_vmalloc_info(self, ram_dump, out_path):
+        vmlist_addr = ram_dump.addr_lookup('vmlist')
+        vmlist = ram_dump.read_word(vmlist_addr)
+
+        vmalloc_out = ram_dump.open_file('vmalloc.txt')
+
+        next_offset = ram_dump.field_offset('struct vm_struct', 'next')
+        addr_offset = ram_dump.field_offset('struct vm_struct', 'addr')
+        size_offset = ram_dump.field_offset('struct vm_struct', 'size')
+        flags_offset = ram_dump.field_offset('struct vm_struct', 'flags')
+        pages_offset = ram_dump.field_offset('struct vm_struct', 'pages')
+        nr_pages_offset = ram_dump.field_offset('struct vm_struct', 'nr_pages')
+        phys_addr_offset = ram_dump.field_offset(
+            'struct vm_struct', 'phys_addr')
+        caller_offset = ram_dump.field_offset('struct vm_struct', 'caller')
+
+        while (vmlist is not None) and (vmlist != 0):
+            addr = ram_dump.read_word(vmlist + addr_offset)
+            caller = ram_dump.read_word(vmlist + caller_offset)
+            nr_pages = ram_dump.read_word(vmlist + nr_pages_offset)
+            phys_addr = ram_dump.read_word(vmlist + phys_addr_offset)
+            flags = ram_dump.read_word(vmlist + flags_offset)
+            size = ram_dump.read_word(vmlist + size_offset)
+
+            vmalloc_str = '{0:x}-{1:x} {2:x}'.format(addr, addr + size, size)
+
+            if (caller != 0):
+                a = ram_dump.unwind_lookup(caller)
+                if a is not None:
+                    symname, offset = a
+                    vmalloc_str = vmalloc_str + \
+                        ' {0}+0x{1:x}'.format(symname, offset)
+
+            if (nr_pages != 0):
+                vmalloc_str = vmalloc_str + ' pages={0}'.format(nr_pages)
+
+            if (phys_addr != 0):
+                vmalloc_str = vmalloc_str + ' phys={0:x}'.format(phys_addr)
+
+            if (flags & VM_IOREMAP) != 0:
+                vmalloc_str = vmalloc_str + ' ioremap'
+
+            if (flags & VM_ALLOC) != 0:
+                vmalloc_str = vmalloc_str + ' vmalloc'
+
+            if (flags & VM_MAP) != 0:
+                vmalloc_str = vmalloc_str + ' vmap'
+
+            if (flags & VM_USERMAP) != 0:
+                vmalloc_str = vmalloc_str + ' user'
+
+            if (flags & VM_VPAGES) != 0:
+                vmalloc_str = vmalloc_str + ' vpages'
+
+            vmalloc_str = vmalloc_str + '\n'
+            vmalloc_out.write(vmalloc_str)
+
+            vmlist = ram_dump.read_word(vmlist + next_offset)
+
+        print_out_str('---wrote vmalloc to vmalloc.txt')
+        vmalloc_out.close()
+
+    def parse(self):
+        out_path = self.ramdump.outdir
+        ver = self.ramdump.version
+        self.print_vmalloc_info(self.ramdump, out_path)
diff --git a/linux-ramdump-parser-v2/parsers/vmstat.py b/linux-ramdump-parser-v2/parsers/vmstat.py
new file mode 100644
index 0000000000000000000000000000000000000000..49cf501388b726b3a3be0ba226496d890b5b0177
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/vmstat.py
@@ -0,0 +1,68 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+
+@register_parser('--print-vmstats', 'Print the information similar to /proc/zoneinfo and /proc/vmstat')
+class ZoneInfo(RamParser):
+
+    def print_zone_stats(self, zone, vmstat_names, max_zone_stats):
+        nr_watermark = self.ramdump.gdbmi.get_value_of('NR_WMARK')
+        wmark_names = self.ramdump.gdbmi.get_enum_lookup_table(
+            'zone_watermarks', nr_watermark)
+
+        zone_name_offset = self.ramdump.field_offset('struct zone', 'name')
+        zname_addr = self.ramdump.read_word(zone + zone_name_offset)
+        zname = self.ramdump.read_cstring(zname_addr, 12)
+
+        zstats_addr = zone + \
+            self.ramdump.field_offset('struct zone', 'vm_stat')
+        zwatermark_addr = zone + \
+            self.ramdump.field_offset('struct zone', 'watermark')
+
+        print_out_str('\nZone {0:8}'.format(zname))
+        for i in xrange(0, max_zone_stats):
+            print_out_str('{0:30}: {1:8}'.format(vmstat_names[i], self.ramdump.read_word(
+                self.ramdump.array_index(zstats_addr, 'atomic_long_t', i))))
+
+        for i in xrange(0, nr_watermark):
+            print_out_str('{0:30}: {1:8}'.format(wmark_names[i], self.ramdump.read_word(
+                self.ramdump.array_index(zwatermark_addr, 'unsigned long', i))))
+
+    def parse(self):
+        max_zone_stats = self.ramdump.gdbmi.get_value_of(
+            'NR_VM_ZONE_STAT_ITEMS')
+        vmstat_names = self.ramdump.gdbmi.get_enum_lookup_table(
+            'zone_stat_item', max_zone_stats)
+        max_nr_zones = self.ramdump.gdbmi.get_value_of('__MAX_NR_ZONES')
+
+        contig_page_data = self.ramdump.addr_lookup('contig_page_data')
+        node_zones_offset = self.ramdump.field_offset(
+            'struct pglist_data', 'node_zones')
+        present_pages_offset = self.ramdump.field_offset(
+            'struct zone', 'present_pages')
+        sizeofzone = self.ramdump.sizeof('struct zone')
+        zone = contig_page_data + node_zones_offset
+
+        while zone < (contig_page_data + node_zones_offset + max_nr_zones * sizeofzone):
+            present_pages = self.ramdump.read_word(zone + present_pages_offset)
+            if not not present_pages:
+                self.print_zone_stats(zone, vmstat_names, max_zone_stats)
+
+            zone = zone + sizeofzone
+
+        print_out_str('\nGlobal Stats')
+        vmstats_addr = self.ramdump.addr_lookup('vm_stat')
+        for i in xrange(0, max_zone_stats):
+            print_out_str('{0:30}: {1:8}'.format(vmstat_names[i], self.ramdump.read_word(
+                self.ramdump.array_index(vmstats_addr, 'atomic_long_t', i))))
diff --git a/linux-ramdump-parser-v2/parsers/watchdog.py b/linux-ramdump-parser-v2/parsers/watchdog.py
new file mode 100644
index 0000000000000000000000000000000000000000..4372170a0588a7a9a0f90034eee566ef76eec6cf
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/watchdog.py
@@ -0,0 +1,391 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+# (name from tz dump, corresponding T32 register, whether or not to print_out_str (the function name))
+tzbsp_register_names = [
+    ('mon_lr', 'pc', True),
+    ('mon_spsr', None, False),
+    ('usr_r0', 'r0', False),
+    ('usr_r1', 'r1', False),
+    ('usr_r2', 'r2', False),
+    ('usr_r3', 'r3', False),
+    ('usr_r4', 'r4', False),
+    ('usr_r5', 'r5', False),
+    ('usr_r6', 'r6', False),
+    ('usr_r7', 'r7', False),
+    ('usr_r8', 'r8', False),
+    ('usr_r9', 'r9', False),
+    ('usr_r10', 'r10', False),
+    ('usr_r11', 'r11', False),
+    ('usr_r12', 'r12', False),
+    ('usr_r13', 'r13_usr', False),
+    ('usr_r14', 'r14_usr', False),
+    ('irq_spsr', 'spsr_irq', False),
+    ('irq_r13', 'r13_irq', False),
+    ('irq_r14', 'r14_irq', True),
+    ('svc_spsr', 'spsr', False),
+    ('svc_r13', 'r13_svc', False),
+    ('svc_r14', 'r14_svc', True),
+    ('abt_spsr', 'spsr_abt', False),
+    ('abt_r13', 'r13_abt', False),
+    ('abt_r14', 'r14_abt', True),
+    ('und_spsr', 'spsr_und', False),
+    ('und_r13', 'r13_und', False),
+    ('und_r14', 'r14_und', True),
+    ('fiq_spsr', 'spsr_fiq', False),
+    ('fiq_r8', 'r8_fiq', False),
+    ('fiq_r9', 'r9_fiq', False),
+    ('fiq_r10', 'r10_fiq', False),
+    ('fiq_r11', 'r11_fiq', False),
+    ('fiq_r12', 'r12_fiq', False),
+    ('fiq_r13', 'r13_fiq', False),
+    ('fiq_r14', 'r14_fiq', False),
+]
+
+
+tzbsp_dump_cpu_ctx_t = ''.join([
+    'I',  # mon_lr
+    'I',  # mon_spsr
+    'I',  # usr_r0
+    'I',  # usr_r1
+    'I',  # usr_r2
+    'I',  # usr_r3
+    'I',  # usr_r4
+    'I',  # usr_r5
+    'I',  # usr_r6
+    'I',  # usr_r7
+    'I',  # usr_r8
+    'I',  # usr_r9
+    'I',  # usr_r10
+    'I',  # usr_r11
+    'I',  # usr_r12
+    'I',  # usr_r13
+    'I',  # usr_r14
+    'I',  # irq_spsr
+    'I',  # irq_r13
+    'I',  # irq_r14
+    'I',  # svc_spsr
+    'I',  # svc_r13
+    'I',  # svc_r14
+    'I',  # abt_spsr
+    'I',  # abt_r13
+    'I',  # abt_r14
+    'I',  # und_spsr
+    'I',  # und_r13
+    'I',  # und_r14
+    'I',  # fiq_spsr
+    'I',  # fiq_r8
+    'I',  # fiq_r9
+    'I',  # fiq_r10
+    'I',  # fiq_r11
+    'I',  # fiq_r12
+    'I',  # fiq_r13
+    'I',  # fiq_r14
+])
+
+tzbsp_dump_buf_t_v2 = ''.join([
+    'I',  # magic
+    'I',  # version
+    'I',  # cpu count
+])
+
+tz_sc_status_ns = 1
+tz_sc_status_wdt = 2
+tz_sc_status_sgi = 4
+
+v2tzbsp_sc_status_ns_bit = 1
+v2tzbsp_sc_status_wdt = 2
+v2tzbsp_sc_status_sgi = 4
+v2tzbsp_sc_status_warm_boot = 8
+
+tz_sc_ignore_status = 0x10
+
+
+v3tzbsp_cpu_dump_status = 0x20
+v3sdi_cpu_dump_status = 0x10
+
+
+class TZCpuCtx():
+
+    def __init__(self, regs_t, version, alt_pc):
+        i = 0
+        self.regs = {}
+        for r in regs_t:
+            # in version 2, mon_lr is not actually useful for HLOS
+            # debugging. Swap it with the alternate if necessary
+            if (version > 1) and i == 0 and alt_pc is not None:
+                r = alt_pc
+            self.regs[tzbsp_register_names[i][0]] = r
+            i += 1
+
+    def print_regs(self, outfile, ramdump):
+        for reg_name, t32_name, print_pc in tzbsp_register_names:
+            if print_pc:
+                a = ramdump.unwind_lookup(self.regs[reg_name])
+                if a is not None:
+                    symname, offset = ramdump.unwind_lookup(
+                        self.regs[reg_name])
+                    pc_string = '[{0}+0x{1:x}]'.format(symname, offset)
+                else:
+                    pc_string = ''
+            else:
+                pc_string = ''
+            print_out_str('   {0} = 0x{1:08x} {2}'.format(
+                reg_name, self.regs[reg_name], pc_string))
+            if t32_name is not None:
+                outfile.write(
+                    'r.s {0} 0x{1:x}\n'.format(t32_name, self.regs[reg_name]))
+
+
+@register_parser('--check-for-watchdog', 'Check for an FIQ watchdog', shortopt='-w')
+class TZRegDump(RamParser):
+
+    def __init__(self, *args):
+        super(TZRegDump, self).__init__(*args)
+        self.sc_status = []
+        self.core_regs = []
+        self.wdt0_status = []
+        self.core_regs = []
+        self.sec_regs = None
+        self.ncores = 0
+        self.version = 0
+        self.mon_sp = []
+        self.wdog_pc = []
+        self.sc_regs = []
+
+    def dump_all_regs(self):
+        for i in range(0, self.ncores):
+            coren_regs = self.ramdump.open_file('core{0}_regs.cmm'.format(i))
+
+            if (self.sc_status[i] & tz_sc_ignore_status) == 0:
+                if self.version == 0:
+                    if (self.sc_status[i] & tz_sc_status_ns):
+                        print_out_str(
+                            'Core {0} was in the non-secure world'.format(i))
+
+                    if (self.sc_status[i] & tz_sc_status_wdt):
+                        print_out_str(
+                            'Core {0} experienced a watchdog timeout'.format(i))
+
+                    if (self.sc_status[i] & tz_sc_status_sgi):
+                        print_out_str(
+                            'Core {0} did not experience a watchdog timeout but some other core did'.format(i))
+                else:
+                    if (self.sc_status[i] & v2tzbsp_sc_status_ns_bit):
+                        print_out_str(
+                            'Core {0} was in the non-secure world'.format(i))
+                    else:
+                        print_out_str(
+                            'Core {0} was in the secure world'.format(i))
+
+                    if (self.sc_status[i] & v2tzbsp_sc_status_sgi):
+                        print_out_str(
+                            'Core {0} received an SGI interrupt'.format(i))
+
+                    if (self.sc_status[i] & v2tzbsp_sc_status_wdt):
+                        print_out_str(
+                            'Core {0} recieved the watchdog interrupt'.format(i))
+
+                    if (self.sc_status[i] & v2tzbsp_sc_status_warm_boot):
+                        print_out_str(
+                            'core {0} has the warm boot flag set'.format(i))
+
+                    print_out_str(
+                        'Core {0} WDT status: {1:x}'.format(i, self.wdt0_status[i]))
+
+            if (self.version >= 3):
+                print_out_str('status:{0}'.format(hex(self.sc_status[i])))
+                if (self.sc_status[i] & v3sdi_cpu_dump_status):
+                    print_out_str(
+                        'SDI dumped CPU context for core {0}'.format(i))
+                elif (self.sc_status[i] & v3tzbsp_cpu_dump_status):
+                    print_out_str(
+                        'TZ dumped CPU context for core {0}'.format(i))
+
+            print_out_str('core{0} regs:'.format(i))
+            self.core_regs[i].print_regs(coren_regs, self.ramdump)
+            coren_regs.close()
+
+        secure_regs = self.ramdump.open_file('secure_world_regs.cmm')
+        print_out_str('\n=============== secure contex ===========')
+        self.sec_regs.print_regs(secure_regs, self.ramdump)
+        print_out_str('============ end secure context ===========')
+        secure_regs.close()
+
+    def dump_core_pc(self, core):
+        if self.version > 1:
+            pc = self.wdog_pc[core]
+        else:
+            pc = self.core_regs[core].regs['mon_lr']
+        lr = self.core_regs[core].regs['svc_r14']
+        a = self.ramdump.unwind_lookup(pc)
+        if a is not None:
+            symname, offset = a
+        else:
+            symname = 'UNKNOWN'
+            offset = 0
+        print_out_str(
+            'Core {3} PC: {0}+{1:x} <{2:x}>'.format(symname, offset, pc, core))
+        a = self.ramdump.unwind_lookup(lr)
+        if a is not None:
+            symname, offset = a
+        else:
+            symname = 'UNKNOWN'
+            offset = 0
+        print_out_str(
+            'Core {3} LR: {0}+{1:x} <{2:x}>'.format(symname, offset, lr, core))
+        print_out_str('')
+        self.ramdump.unwind.unwind_backtrace(
+            self.core_regs[core].regs['svc_r13'], 0, pc, lr, '')
+        print_out_str('')
+
+    def init_regs(self, ebi_addr):
+        cpu_count = 0
+        status = self.ramdump.read_string(ebi_addr, tzbsp_dump_buf_t_v2, False)
+
+        if status is None:
+            print_out_str("!!! Couldn't read from {0:x}!".format(ebi_addr))
+            print_out_str('!!! No FIQ information will be parsed')
+            print_out_str(
+                '!!! Do you need to specify a different offset for TZ?')
+            return False
+
+        if status[0] == 0x44434151:
+            cpu_count = status[2]
+            version = status[1]
+            ebi_addr += struct.calcsize(tzbsp_dump_buf_t_v2)
+        else:
+            cpu_count = 2
+            version = 0
+
+        print_out_str('running dump version {0}'.format(version))
+        for i in range(0, cpu_count):
+            self.sc_status.append(self.ramdump.read_word(ebi_addr, False))
+            ebi_addr += 4
+
+        for i in range(0, cpu_count):
+            self.sc_regs.append(
+                self.ramdump.read_string(ebi_addr, tzbsp_dump_cpu_ctx_t, False))
+            ebi_addr += struct.calcsize(tzbsp_dump_cpu_ctx_t)
+            # new versions have extra data
+            if version > 1:
+                self.mon_sp.append(self.ramdump.read_word(ebi_addr, False))
+                self.wdog_pc.append(
+                    self.ramdump.read_word(ebi_addr + 4, False))
+                ebi_addr += 8
+
+        sc_secure = self.ramdump.read_string(
+            ebi_addr, tzbsp_dump_cpu_ctx_t, False)
+        ebi_addr += struct.calcsize(tzbsp_dump_cpu_ctx_t)
+
+        for i in range(0, cpu_count):
+            self.wdt0_status.append(self.ramdump.read_word(ebi_addr, False))
+            ebi_addr += 4
+
+        if version > 1:
+            for regs, p in zip(self.sc_regs, self.wdog_pc):
+                self.core_regs.append(TZCpuCtx(regs, version, p))
+        else:
+            for regs in self.sc_regs:
+                self.core_regs.append(TZCpuCtx(regs, version, None))
+        self.sec_regs = TZCpuCtx(sc_secure, version, None)
+        self.ncores = cpu_count
+        self.version = version
+        return True
+
+    def parse(self):
+        ebi_addr = self.ramdump.read_tz_offset()
+
+        if ebi_addr is None:
+            print_out_str(
+                '!!! Could not read from IMEM at address {0:x}'.format(self.ramdump.tz_addr))
+            return None
+
+        if (ebi_addr == 0):
+            print_out_str(
+                '!!! No EBI address at IMEM location {0:x}.'.format(self.ramdump.tz_addr))
+            print_out_str('!!! No FIQ occured on this system')
+            return None
+
+        print_out_str(
+            '[!!!!] Read {0:x} from IMEM successfully!'.format(ebi_addr))
+        print_out_str('[!!!!] An FIQ occured on the system!')
+
+        # The debug image will be responsible for printing out the register
+        # information, no need to print it twice
+        if self.ramdump.is_config_defined('CONFIG_MSM_DEBUG_IMAGE'):
+            print_out_str(
+                '[!!!!] Debug image was enabled, the contexts will be printed there')
+            return
+
+        regs = self.init_regs(ebi_addr)
+        if regs is False:
+            print_out_str('!!! Could not get registers from TZ dump')
+            return
+
+        for i in range(self.ncores):
+            self.dump_core_pc(i)
+        self.dump_all_regs()
+
+
+def get_wdog_timing(ramdump):
+    jiffies_addr = ramdump.addr_lookup('jiffies')
+    last_ns_addr = ramdump.addr_lookup('last_ns')
+    last_pet_addr = ramdump.addr_lookup('last_pet')
+    pet_delay_time_addr = ramdump.addr_lookup('delay_time')
+    dogstruct_addr = ramdump.addr_lookup('dogwork_struct')
+
+    timer_offset = ramdump.field_offset('struct delayed_work', 'timer')
+    timer_expires_offset = ramdump.field_offset(
+        'struct timer_list', 'expires')
+
+    timer_expires = ramdump.read_word(
+        dogstruct_addr + timer_offset + timer_expires_offset)
+    jiffies = ramdump.read_word(jiffies_addr)
+    if (timer_expires > jiffies):
+        print_out_str('Pet function to be scheduled in {0} seconds'.format(
+            (timer_expires - jiffies) * 0.01))
+    else:
+        print_out_str('Pet function may have been blocked.')
+        print_out_str('Jiffies is {0} seconds after when  it was supposed to be scheduled'.format(
+            (jiffies - timer_expires) * 0.01))
+
+    if (last_ns_addr != 0) and (last_pet_addr != 0) and (pet_delay_time_addr != 0):
+        last_ns = ramdump.read_dword(last_ns_addr)
+        last_pet = ramdump.read_dword(last_pet_addr)
+        pet_delay_time = ramdump.read_word(pet_delay_time_addr)
+
+        diff = last_ns - last_pet
+
+        print_out_str('Most recent time that the watchdog was pet: {0}.{1:6}'.format(
+            last_pet / 1000000000, last_pet % 1000000000))
+        print_out_str('Most recent timestamp read from the timer hardware: {0}.{1:6}'.format(
+            last_ns / 1000000000, last_ns % 1000000000))
+        if (last_ns > last_pet):
+            print_out_str(
+                'Pet delay time in this build is {0} seconds'.format((pet_delay_time * 10) / 1000))
+            print_out_str('The watchdog was not pet for at least {0}.{1:6} seconds'.format(
+                diff / 1000000000, diff % 1000000000))
+
+        print_out_str(
+            '!!! The difference between the two timestamps above is NOT')
+        print_out_str(
+            '!!! to be used to determine whether a watchdog bite occured')
+
+    elif (last_pet_addr):
+        last_pet = ramdump.read_dword(last_pet_addr)
+        print_out_str('Most recent time that the watchdgo was pet: {0}.{1:6}'.format(
+            last_pet / 1000000000, last_pet % 1000000000))
+        print_out_str('The watchdog was not pet for at least {0}.{1:6} seconds'.format(
+            pet_delay_diff / 1000000000, pet_delay_diff % 1000000000))
diff --git a/linux-ramdump-parser-v2/parsers/workqueue.py b/linux-ramdump-parser-v2/parsers/workqueue.py
new file mode 100644
index 0000000000000000000000000000000000000000..b1170a560c4e6193e4606893af559c71b03adfb1
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/workqueue.py
@@ -0,0 +1,500 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import re
+from print_out import print_out_str
+from parser_util import register_parser, RamParser
+
+
+@register_parser('--print-workqueues', 'Print the state of the workqueues', shortopt='-q')
+class Workqueues(RamParser):
+
+    def print_workqueue_state_3_0(self, ram_dump):
+        per_cpu_offset_addr = ram_dump.addr_lookup('__per_cpu_offset')
+        global_cwq_sym_addr = ram_dump.addr_lookup('global_cwq')
+        system_wq_addr = ram_dump.addr_lookup('system_long_wq')
+
+        idle_list_offset = ram_dump.field_offset(
+            'struct global_cwq', 'idle_list')
+        worklist_offset = ram_dump.field_offset(
+            'struct global_cwq', 'worklist')
+        busy_hash_offset = ram_dump.field_offset(
+            'struct global_cwq', 'busy_hash')
+        scheduled_offset = ram_dump.field_offset('struct worker', 'scheduled')
+        worker_task_offset = ram_dump.field_offset('struct worker', 'task')
+        worker_entry_offset = ram_dump.field_offset('struct worker', 'entry')
+        offset_comm = ram_dump.field_offset('struct task_struct', 'comm')
+        work_entry_offset = ram_dump.field_offset(
+            'struct work_struct', 'entry')
+        work_hentry_offset = ram_dump.field_offset('struct worker', 'hentry')
+        work_func_offset = ram_dump.field_offset('struct work_struct', 'func')
+        current_work_offset = ram_dump.field_offset(
+            'struct worker', 'current_work')
+        cpu_wq_offset = ram_dump.field_offset(
+            'struct workqueue_struct', 'cpu_wq')
+        unbound_gcwq_addr = ram_dump.addr_lookup('unbound_global_cwq')
+
+        if per_cpu_offset_addr is None:
+            per_cpu_offset0 = 0
+            per_cpu_offset1 = 0
+        else:
+            per_cpu_offset0 = ram_dump.read_word(per_cpu_offset_addr)
+            per_cpu_offset1 = ram_dump.read_word(per_cpu_offset_addr + 4)
+
+        global_cwq_cpu0_addr = global_cwq_sym_addr + per_cpu_offset0
+
+        idle_list_addr0 = ram_dump.read_word(
+            global_cwq_cpu0_addr + idle_list_offset)
+        idle_list_addr1 = ram_dump.read_word(
+            unbound_gcwq_addr + idle_list_offset)
+
+        worklist_addr0 = ram_dump.read_word(
+            global_cwq_cpu0_addr + worklist_offset)
+        worklist_addr1 = ram_dump.read_word(
+            unbound_gcwq_addr + worklist_offset)
+
+        s = '<'
+        for a in range(0, 64):
+            s = s + 'I'
+
+        busy_hash0 = ram_dump.read_string(
+            global_cwq_cpu0_addr + busy_hash_offset, s)
+        busy_hash1 = ram_dump.read_string(
+            unbound_gcwq_addr + busy_hash_offset, s)
+        busy_hash = []
+        for a in busy_hash0:
+            busy_hash.append(a)
+
+        for a in busy_hash1:
+            busy_hash.append(a)
+
+        for k in range(0, 128):
+            next_busy_worker = busy_hash[k]
+            if busy_hash[k] != 0:
+                cnt = 0
+                while True:
+                    worker_addr = next_busy_worker - work_hentry_offset
+                    worker_task_addr = ram_dump.read_word(
+                        worker_addr + worker_task_offset)
+                    if worker_task_addr is None or worker_task_addr == 0:
+                        break
+                    taskname = ram_dump.read_cstring(
+                        worker_task_addr + offset_comm, 16)
+                    scheduled_addr = ram_dump.read_word(
+                        worker_addr + scheduled_offset)
+                    current_work_addr = ram_dump.read_word(
+                        worker_addr + current_work_offset)
+                    current_work_func = ram_dump.read_word(
+                        current_work_addr + work_func_offset)
+                    wname = ram_dump.unwind_lookup(current_work_func)
+                    if wname is not None:
+                        worker_name, a = wname
+                    else:
+                        worker_name = 'Worker at 0x{0:x}'.format(
+                            current_work_func)
+                    print_out_str(
+                        'BUSY Workqueue worker: {0} current_work: {1}'.format(taskname, worker_name))
+                    if cnt > 200:
+                        break
+                    cnt += 1
+                    next_busy_worker = ram_dump.read_word(
+                        worker_addr + work_hentry_offset)
+                    if next_busy_worker == 0:
+                        break
+
+        for i in (0, 1):
+            if i == 0:
+                idle_list_addr = idle_list_addr0
+            else:
+                idle_list_addr = idle_list_addr1
+            next_entry = idle_list_addr
+            while True:
+                worker_addr = next_entry - worker_entry_offset
+                worker_task_addr = ram_dump.read_word(
+                    next_entry - worker_entry_offset + worker_task_offset)
+                if worker_task_addr is None or worker_task_addr == 0:
+                    break
+
+                taskname = ram_dump.read_cstring(
+                    (worker_task_addr + offset_comm), 16)
+                scheduled_addr = ram_dump.read_word(
+                    worker_addr + scheduled_offset)
+                current_work_addr = ram_dump.read_word(
+                    worker_addr + current_work_offset)
+                next_entry = ram_dump.read_word(next_entry)
+                if current_work_addr != 0:
+                    current_work_func = ram_dump.read_word(
+                        current_work_addr + work_func_offset)
+                    wname = ram_dump.unwind_lookup(current_work_func)
+                    if wname is not None:
+                        current_work_name, foo = wname
+                    else:
+                        current_work_name = 'worker at 0x{0:x}'.format(
+                            current_work_func)
+                else:
+                    current_work_func = 0
+                    current_work_name = '(null)'
+
+                if next_entry == idle_list_addr:
+                    break
+
+                print_out_str('IDLE Workqueue worker: {0} current_work: {1}'.format(
+                    taskname, current_work_name))
+                if scheduled_addr == (worker_addr + scheduled_offset):
+                    continue
+
+                if (next_entry == idle_list_addr):
+                    break
+
+        print_out_str('Pending workqueue info')
+        for i in (0, 1):
+            if i == 0:
+                worklist_addr = worklist_addr0
+            else:
+                worklist_addr = worklist_addr1
+            next_work_entry = worklist_addr
+            while True:
+                work_func_addr = ram_dump.read_word(
+                    next_work_entry - work_entry_offset + work_func_offset)
+                next_work_temp = ram_dump.read_word(next_work_entry)
+                if next_work_temp == next_work_entry:
+                    print_out_str('!!! Cycle in workqueue!')
+                    break
+                next_work_entry = next_work_temp
+
+                if ram_dump.virt_to_phys(work_func_addr) != 0:
+                    wname = ram_dump.unwind_lookup(work_func_addr)
+                    if wname is not None:
+                        work_func_name, foo = wname
+                    else:
+                        work_func_name = 'worker at 0x{0:x}'.format(
+                            work_func_addr)
+                    if i == 0:
+                        print_out_str(
+                            'Pending unbound entry: {0}'.format(work_func_name))
+                    else:
+                        print_out_str(
+                            'Pending bound entry: {0}'.format(work_func_name))
+                if next_work_entry == worklist_addr:
+                    break
+
+    def print_workqueue_state_3_7(self, ram_dump):
+        per_cpu_offset_addr = ram_dump.addr_lookup('__per_cpu_offset')
+        global_cwq_sym_addr = ram_dump.addr_lookup('global_cwq')
+
+        pools_offset = ram_dump.field_offset('struct global_cwq', 'pools')
+        worklist_offset = ram_dump.field_offset(
+            'struct global_cwq', 'worklist')
+        busy_hash_offset = ram_dump.field_offset(
+            'struct global_cwq', 'busy_hash')
+        scheduled_offset = ram_dump.field_offset('struct worker', 'scheduled')
+        worker_task_offset = ram_dump.field_offset('struct worker', 'task')
+        worker_entry_offset = ram_dump.field_offset('struct worker', 'entry')
+        offset_comm = ram_dump.field_offset('struct task_struct', 'comm')
+        work_entry_offset = ram_dump.field_offset(
+            'struct work_struct', 'entry')
+        work_hentry_offset = ram_dump.field_offset('struct worker', 'hentry')
+        work_func_offset = ram_dump.field_offset('struct work_struct', 'func')
+        current_work_offset = ram_dump.field_offset(
+            'struct worker', 'current_work')
+        cpu_wq_offset = ram_dump.field_offset(
+            'struct workqueue_struct', 'cpu_wq')
+        pool_idle_offset = ram_dump.field_offset(
+            'struct worker_pool', 'idle_list')
+        worker_pool_size = ram_dump.sizeof('struct worker_pool')
+        pending_work_offset = ram_dump.field_offset(
+            'struct worker_pool', 'worklist')
+        unbound_gcwq_addr = ram_dump.addr_lookup('unbound_global_cwq')
+        cpu_present_bits_addr = ram_dump.addr_lookup('cpu_present_bits')
+        cpu_present_bits = ram_dump.read_word(cpu_present_bits_addr)
+        cpus = bin(cpu_present_bits).count('1')
+
+        s = '<'
+        for a in range(0, 64):
+            s = s + 'I'
+
+        for i in range(0, cpus):
+            busy_hash = []
+            if per_cpu_offset_addr is None:
+                offset = 0
+            else:
+                offset = ram_dump.read_word(per_cpu_offset_addr + 4 * i)
+            workqueue_i = global_cwq_sym_addr + offset
+            busy_hashi = ram_dump.read_string(
+                workqueue_i + busy_hash_offset, s)
+            for a in busy_hashi:
+                busy_hash.append(a)
+
+            for k in range(0, 64):
+                next_busy_worker = busy_hash[k]
+                if busy_hash[k] != 0:
+                    cnt = 0
+
+                    while True:
+                        worker_addr = next_busy_worker - work_hentry_offset
+                        worker_task_addr = ram_dump.read_word(
+                            worker_addr + worker_task_offset)
+                        if worker_task_addr is None or worker_task_addr == 0:
+                            break
+                        taskname = ram_dump.read_cstring(
+                            worker_task_addr + offset_comm, 16)
+                        scheduled_addr = ram_dump.read_word(
+                            worker_addr + scheduled_offset)
+                        current_work_addr = ram_dump.read_word(
+                            worker_addr + current_work_offset)
+                        current_work_func = ram_dump.read_word(
+                            current_work_addr + work_func_offset)
+                        wname = ram_dump.unwind_lookup(current_work_func)
+                        if wname is not None:
+                            worker_name, a = wname
+                        else:
+                            worker_name = 'Worker at 0x{0:x}'.format(
+                                current_work_func)
+                        print_out_str(
+                            'BUSY Workqueue worker: {0} current_work: {1}'.format(taskname, worker_name))
+                        if cnt > 200:
+                            break
+                        cnt += 1
+                        next_busy_worker = ram_dump.read_word(
+                            worker_addr + work_hentry_offset)
+                        if next_busy_worker == 0:
+                            break
+
+            worker_pool = workqueue_i + pools_offset
+            # Need better way to ge the number of pools...
+            for k in range(0, 2):
+                worker_pool_i = worker_pool + k * worker_pool_size
+
+                idle_list_addr = worker_pool_i + pool_idle_offset
+                next_entry = ram_dump.read_word(idle_list_addr)
+                while True:
+                    worker_addr = next_entry - worker_entry_offset
+                    worker_task_addr = ram_dump.read_word(
+                        next_entry - worker_entry_offset + worker_task_offset)
+                    if worker_task_addr is None or worker_task_addr == 0:
+                        break
+
+                    taskname = ram_dump.read_cstring(
+                        (worker_task_addr + offset_comm), 16)
+                    scheduled_addr = ram_dump.read_word(
+                        worker_addr + scheduled_offset)
+                    current_work_addr = ram_dump.read_word(
+                        worker_addr + current_work_offset)
+                    next_entry = ram_dump.read_word(next_entry)
+                    if current_work_addr != 0:
+                        current_work_func = ram_dump.read_word(
+                            current_work_addr + work_func_offset)
+                        wname = ram_dump.unwind_lookup(current_work_func)
+                        if wname is not None:
+                            current_work_name, foo = wname
+                        else:
+                            current_work_name = 'worker at 0x{0:x}'.format(
+                                current_work_func)
+                    else:
+                        current_work_func = 0
+                        current_work_name = '(null)'
+
+                    if next_entry == idle_list_addr:
+                        break
+
+                    print_out_str(
+                        'IDLE Workqueue worker: {0} current_work: {1}'.format(taskname, current_work_name))
+                    if scheduled_addr == (worker_addr + scheduled_offset):
+                        continue
+
+                    if (next_entry == idle_list_addr):
+                        break
+
+                worklist_addr = worker_pool_i + pending_work_offset
+                next_work_entry = worklist_addr
+                while ram_dump.read_word(next_work_entry) != next_work_entry:
+                    work_func_addr = ram_dump.read_word(
+                        next_work_entry - work_entry_offset + work_func_offset)
+                    next_work_temp = ram_dump.read_word(next_work_entry)
+                    if next_work_temp == next_work_entry:
+                        print_out_str('!!! Cycle in workqueue!')
+                        break
+                    next_work_entry = next_work_temp
+
+                    if ram_dump.virt_to_phys(work_func_addr) != 0:
+                        work_func_name, foo = ram_dump.unwind_lookup(
+                            work_func_addr)
+                        if i == 0:
+                            print_out_str(
+                                'Pending unbound entry: {0}'.format(work_func_name))
+                        else:
+                            print_out_str(
+                                'Pending bound entry: {0}'.format(work_func_name))
+                    if next_work_entry == worklist_addr:
+                        break
+
+    def print_workqueue_state_3_10(self, ram_dump):
+        print_out_str(
+            '======================= WORKQUEUE STATE ============================')
+        per_cpu_offset_addr = ram_dump.addr_lookup('__per_cpu_offset')
+        cpu_worker_pools_addr = ram_dump.addr_lookup('cpu_worker_pools')
+
+        busy_hash_offset = ram_dump.field_offset(
+            'struct worker_pool', 'busy_hash')
+        scheduled_offset = ram_dump.field_offset('struct worker', 'scheduled')
+        worker_task_offset = ram_dump.field_offset('struct worker', 'task')
+        worker_entry_offset = ram_dump.field_offset('struct worker', 'entry')
+        offset_comm = ram_dump.field_offset('struct task_struct', 'comm')
+        work_entry_offset = ram_dump.field_offset(
+            'struct work_struct', 'entry')
+        work_hentry_offset = ram_dump.field_offset('struct worker', 'hentry')
+        work_func_offset = ram_dump.field_offset('struct work_struct', 'func')
+        current_work_offset = ram_dump.field_offset(
+            'struct worker', 'current_work')
+        pool_idle_offset = ram_dump.field_offset(
+            'struct worker_pool', 'idle_list')
+        worker_pool_size = ram_dump.sizeof('struct worker_pool')
+        pending_work_offset = ram_dump.field_offset(
+            'struct worker_pool', 'worklist')
+        cpu_present_bits_addr = ram_dump.addr_lookup('cpu_present_bits')
+        cpu_present_bits = ram_dump.read_word(cpu_present_bits_addr)
+        cpus = bin(cpu_present_bits).count('1')
+
+        s = '<'
+        for a in range(0, 64):
+            s = s + 'I'
+
+        for i in range(0, cpus):
+            busy_hash = []
+            if per_cpu_offset_addr is None:
+                offset = 0
+            else:
+                offset = ram_dump.read_word(per_cpu_offset_addr + 4 * i)
+
+            worker_pool = cpu_worker_pools_addr + offset
+            # Need better way to ge the number of pools...
+            for k in range(0, 2):
+                worker_pool_i = worker_pool + k * worker_pool_size
+                busy_hashi = ram_dump.read_string(
+                    worker_pool_i + busy_hash_offset, s)
+                for a in busy_hashi:
+                    busy_hash.append(a)
+
+                for k in range(0, 64):
+                    next_busy_worker = busy_hash[k]
+                    if busy_hash[k] != 0:
+                        cnt = 0
+
+                        while True:
+                            worker_addr = next_busy_worker - work_hentry_offset
+                            worker_task_addr = ram_dump.read_word(
+                                worker_addr + worker_task_offset)
+                            if worker_task_addr is None or worker_task_addr == 0:
+                                break
+                            taskname = ram_dump.read_cstring(
+                                worker_task_addr + offset_comm, 16)
+                            scheduled_addr = ram_dump.read_word(
+                                worker_addr + scheduled_offset)
+                            current_work_addr = ram_dump.read_word(
+                                worker_addr + current_work_offset)
+                            current_work_func = ram_dump.read_word(
+                                current_work_addr + work_func_offset)
+                            wname = ram_dump.unwind_lookup(current_work_func)
+                            if wname is not None:
+                                worker_name, a = wname
+                            else:
+                                worker_name = 'Worker at 0x{0:x}'.format(
+                                    current_work_func)
+                            print_out_str(
+                                'BUSY Workqueue worker: {0} current_work: {1}'.format(taskname, worker_name))
+                            if cnt > 200:
+                                break
+                            cnt += 1
+                            next_busy_worker = ram_dump.read_word(
+                                worker_addr + work_hentry_offset)
+                            if next_busy_worker == 0:
+                                break
+
+                idle_list_addr = worker_pool_i + pool_idle_offset
+                next_entry = ram_dump.read_word(idle_list_addr)
+                while True:
+                    worker_addr = next_entry - worker_entry_offset
+                    worker_task_addr = ram_dump.read_word(
+                        next_entry - worker_entry_offset + worker_task_offset)
+                    if worker_task_addr is None or worker_task_addr == 0:
+                        break
+
+                    taskname = ram_dump.read_cstring(
+                        (worker_task_addr + offset_comm), 16)
+                    scheduled_addr = ram_dump.read_word(
+                        worker_addr + scheduled_offset)
+                    current_work_addr = ram_dump.read_word(
+                        worker_addr + current_work_offset)
+                    next_entry = ram_dump.read_word(next_entry)
+                    if current_work_addr != 0:
+                        current_work_func = ram_dump.read_word(
+                            current_work_addr + work_func_offset)
+                        wname = ram_dump.unwind_lookup(current_work_func)
+                        if wname is not None:
+                            current_work_name, foo = wname
+                        else:
+                            current_work_name = 'worker at 0x{0:x}'.format(
+                                current_work_func)
+                    else:
+                        current_work_func = 0
+                        current_work_name = '(null)'
+
+                    if next_entry == idle_list_addr:
+                        break
+
+                    print_out_str(
+                        'IDLE Workqueue worker: {0} current_work: {1}'.format(taskname, current_work_name))
+                    if scheduled_addr == (worker_addr + scheduled_offset):
+                        continue
+
+                    if (next_entry == idle_list_addr):
+                        break
+
+                worklist_addr = worker_pool_i + pending_work_offset
+                next_work_entry = worklist_addr
+                while ram_dump.read_word(next_work_entry) != next_work_entry:
+                    work_func_addr = ram_dump.read_word(
+                        next_work_entry - work_entry_offset + work_func_offset)
+                    next_work_temp = ram_dump.read_word(next_work_entry)
+                    if next_work_temp == next_work_entry:
+                        print_out_str('!!! Cycle in workqueue!')
+                        break
+                    next_work_entry = next_work_temp
+
+                    if ram_dump.virt_to_phys(work_func_addr) != 0:
+                        work_func_name, foo = ram_dump.unwind_lookup(
+                            work_func_addr)
+                        if i == 0:
+                            print_out_str(
+                                'Pending unbound entry: {0}'.format(work_func_name))
+                        else:
+                            print_out_str(
+                                'Pending bound entry: {0}'.format(work_func_name))
+                    if next_work_entry == worklist_addr:
+                        break
+
+    def parse(self):
+            ver = self.ramdump.version
+            if re.search('3.0.\d', ver) is not None:
+                    print_workqueue_state_3_0(self.ramdump)
+            if re.search('3.4.\d', ver) is not None:
+                    # somebody did a backport of 3.7 workqueue patches to msm so
+                    # need to detect new vs. old versions
+                    idle_list_offset = self.ramdump.field_offset(
+                        'struct global_cwq', 'idle_list')
+                    if idle_list_offset is None:
+                        self.print_workqueue_state_3_7(self.ramdump)
+                    else:
+                        self.print_workqueue_state_3_4(self.ramdump)
+            if re.search('3.7.\d', ver) is not None:
+                    self.print_workqueue_state_3_7(self.ramdump)
+            if re.search('3.10.\d', ver) is not None:
+                    self.print_workqueue_state_3_10(self.ramdump)
diff --git a/linux-ramdump-parser-v2/print_out.py b/linux-ramdump-parser-v2/print_out.py
new file mode 100644
index 0000000000000000000000000000000000000000..51370a7aca61a3c6ba55255323e48f9d15de74e2
--- /dev/null
+++ b/linux-ramdump-parser-v2/print_out.py
@@ -0,0 +1,46 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+import sys
+from contextlib import contextmanager
+
+out_file = None
+
+
+def set_outfile(path):
+    global out_file
+    try:
+        out_file = open(path, 'wb')
+    except:
+        print_out_str("could not open path {0}".format(path))
+        print_out_str("Do you have write/read permissions on the path?")
+        sys.exit(1)
+
+
+def print_out_str(string):
+    if out_file is None:
+        print (string)
+    else:
+        out_file.write((string + '\n').encode('ascii', 'ignore'))
+
+
+@contextmanager
+def print_out_section(header):
+    begin_header_string = '{0}begin {1}{0}'.format(
+        10 * '-', header
+    )
+    end_header_string = '{0}end {1}{2}'.format(
+        12 * '-',
+        header,
+        10 * '-',
+    )
+    print_out_str('\n' + begin_header_string)
+    yield
+    print_out_str(end_header_string + '\n')
diff --git a/linux-ramdump-parser-v2/qdss.py b/linux-ramdump-parser-v2/qdss.py
new file mode 100644
index 0000000000000000000000000000000000000000..a100d2f140c42b28e239bd34444548b317638aa1
--- /dev/null
+++ b/linux-ramdump-parser-v2/qdss.py
@@ -0,0 +1,343 @@
+# Copyright (c) 2012, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+from print_out import print_out_str
+
+tmc_registers = {
+    'RSZ': (0x004, 'RAM Size'),
+    'STS': (0x00C, 'Status Register'),
+    'RRD': (0x010, 'RAM Read Data Register'),
+    'RRP': (0x014, 'RAM Read Pointer Register'),
+    'RWP': (0x018, 'RAM Write Pointer Register'),
+    'TRG': (0x01C, 'Trigger Counter Register'),
+    'CTL': (0x020, 'Control Register'),
+    'RWD': (0x024, 'RAM Write Data Register'),
+    'MODE': (0x028, 'Mode Register'),
+    'LBUFLEVEL': (0x02C, 'Latched Buffer Fill Level'),
+    'CBUFLEVEL': (0x030, 'Current Buffer Fill Level'),
+    'BUFWM': (0x034, 'Buffer Level Water Mark'),
+    'RRPHI': (0x038, 'RAM Read Pointer High Register'),
+    'RWPHI': (0x03C, 'RAM Write Pointer High Register'),
+    'AXICTL': (0x110, 'AXI Control Register'),
+    'DBALO': (0x118, 'Data Buffer Address Low Register'),
+    'DBAHI': (0x11C, 'Data Buffer Address High Register'),
+    'FFSR': (0x300, 'Formatter and Flush Status Register'),
+    'FFCR': (0x304, 'Formatter and Flush Control Register'),
+    'PSCR': (0x308, 'Periodic Synchronization Counter Register'),
+    'ITATBMDATA0': (0xED0, 'Integration Test ATB Master Data Register 0'),
+    'ITATBMCTR2': (0xED4, 'Integration Test ATB Master Interface Control 2 Register'),
+    'ITATBMCTR1': (0xED8, 'Integration Test ATB Master Control Register 1'),
+    'ITATBMCTR0': (0xEDC, 'Integration Test ATB Master Interface Control 0 Register'),
+    'ITMISCOP0': (0xEE0, 'Integration Test Miscellaneous Output Register 0'),
+    'ITTRFLIN': (0xEE8, 'Integration Test Trigger In and Flush In Register'),
+    'ITATBDATA0': (0xEEC, 'Integration Test ATB Data Register 0'),
+    'ITATBCTR2': (0xEF0, 'Integration Test ATB Control 2 Register'),
+    'ITATBCTR1': (0xEF4, 'Integration Test ATB Control 1 Register'),
+    'ITATBCTR0': (0xEF8, 'Integration Test ATB Control 0 Register'),
+    'ITCTRL': (0xF00, 'Integration Mode Control Register'),
+    'CLAIMSET': (0xFA0, 'Claim Tag Set Register'),
+    'CLAIMCLR': (0xFA4, 'Claim Tag Clear Register'),
+    'LAR': (0xFB0, 'Lock Access Register'),
+    'LSR': (0xFB4, 'Lock Status Register'),
+    'AUTHSTATUS': (0xFB8, 'Authentication Status Register'),
+    'DEVID': (0xFC8, 'Device Configuration Register'),
+    'DEVTYPE': (0xFCC, 'Device Type Identifier Register'),
+    'PERIPHID4': (0xFD0, 'Peripheral ID4 Register'),
+    'PERIPHID5': (0xFD4, 'Peripheral ID5 Register'),
+    'PERIPHID6': (0xFD8, 'Peripheral ID6 Register'),
+    'PERIPHID7': (0xFDC, 'Peripheral ID7 Register'),
+    'PERIPHID0': (0xFE0, 'Peripheral ID0 Register'),
+    'PERIPHID1': (0xFE4, 'Peripheral ID1 Register'),
+    'PERIPHID2': (0xFE8, 'Peripheral ID2 Register'),
+    'PERIPHID3': (0xFEC, 'Peripheral ID3 Register'),
+    'COMPID0': (0xFF0, 'Component ID0 Register'),
+    'COMPID1': (0xFF4, 'Component ID1 Register'),
+    'COMPID2': (0xFF8, 'Component ID2 Register'),
+    'COMPID3': (0xFFC, 'Component ID3 Register'),
+}
+
+etm_registers = {
+    'ETMCR': (0x000, 'Main Control Register'),
+    'ETMCCR': (0x001, 'Configuration Code Register'),
+    'ETMTRIGGER': (0x002, 'Trigger Event Register'),
+    'ETMSR': (0x004, 'Status Register'),
+    'ETMCSR': (0x005, 'System Configuration Register'),
+    'ETMTSSCR': (0x006, 'TraceEnable Start/Stop Control Register'),
+    'ETMTEEVR': (0x008, 'TraceEnable Event Register'),
+    'ETMTECR1': (0x009, 'TraceEnable Control Register'),
+    'ETMFFLR': (0x00B, 'FIFOFULL Level Register'),
+    'ETMACVR0': (0x10, 'Address Comparator Value Register 0'),
+    'ETMACVR1': (0x11, 'Address Comparator Value Register 1'),
+    'ETMACVR2': (0x12, 'Address Comparator Value Register 2'),
+    'ETMACVR3': (0x13, 'Address Comparator Value Register 3'),
+    'ETMACVR4': (0x14, 'Address Comparator Value Register 4'),
+    'ETMACVR5': (0x15, 'Address Comparator Value Register 5'),
+    'ETMACVR6': (0x16, 'Address Comparator Value Register 6'),
+    'ETMACVR7': (0x17, 'Address Comparator Value Register 7'),
+    'ETMACVR8': (0x18, 'Address Comparator Value Register 8'),
+    'ETMACVR9': (0x19, 'Address Comparator Value Register 9'),
+    'ETMACVRA': (0x1A, 'Address Comparator Value Register A'),
+    'ETMACVRB': (0x1B, 'Address Comparator Value Register B'),
+    'ETMACVRC': (0x1C, 'Address Comparator Value Register C'),
+    'ETMACVRD': (0x1D, 'Address Comparator Value Register D'),
+    'ETMACVRE': (0x1E, 'Address Comparator Value Register E'),
+    'ETMACVRF': (0x1F, 'Address Comparator Value Register F'),
+
+    'ETMACVT0': (0x20, 'Address Comparator Type Register 0'),
+    'ETMACVT1': (0x21, 'Address Comparator Type Register 1'),
+    'ETMACVT2': (0x22, 'Address Comparator Type Register 2'),
+    'ETMACVT3': (0x23, 'Address Comparator Type Register 3'),
+    'ETMACVT4': (0x24, 'Address Comparator Type Register 4'),
+    'ETMACVT5': (0x25, 'Address Comparator Type Register 5'),
+    'ETMACVT6': (0x26, 'Address Comparator Type Register 6'),
+    'ETMACVT7': (0x27, 'Address Comparator Type Register 7'),
+    'ETMACVT8': (0x28, 'Address Comparator Type Register 8'),
+    'ETMACVT9': (0x29, 'Address Comparator Type Register 9'),
+    'ETMACVTA': (0x2A, 'Address Comparator Type Register A'),
+    'ETMACVTB': (0x2B, 'Address Comparator Type Register B'),
+    'ETMACVTC': (0x2C, 'Address Comparator Type Register C'),
+    'ETMACVTD': (0x2D, 'Address Comparator Type Register D'),
+    'ETMACVTE': (0x2E, 'Address Comparator Type Register E'),
+    'ETMACVTF': (0x2F, 'Address Comparator Type Register F'),
+
+    'ETMCNTRLDVR0': (0x050, 'Counter Reload Value Register 0'),
+    'ETMCNTRLDVR1': (0x051, 'Counter Reload Value Register 1'),
+    'ETMCNTRLDVR2': (0x052, 'Counter Reload Value Register 2'),
+    'ETMCNTRLDVR3': (0x053, 'Counter Reload Value Register 3'),
+
+    'ETMCNTRENR0': (0x054, 'Counter Enable Event Register 0'),
+    'ETMCNTRENR1': (0x055, 'Counter Enable Event Register 1'),
+    'ETMCNTRENR2': (0x056, 'Counter Enable Event Register 2'),
+    'ETMCNTRENR3': (0x057, 'Counter Enable Event Register 3'),
+
+    'ETMCNTRLDEVR0': (0x058, 'Counter Reload Event Registers 0'),
+    'ETMCNTRLDEVR1': (0x059, 'Counter Reload Event Registers 1'),
+    'ETMCNTRLDEVR2': (0x05A, 'Counter Reload Event Registers 2'),
+    'ETMCNTRLDEVR3': (0x05B, 'Counter Reload Event Registers 3'),
+
+    'ETMCNTVR0': (0x05C, 'Counter Value Register 0'),
+    'ETMCNTVR1': (0x05D, 'Counter Value Register 1'),
+    'ETMCNTVR2': (0x05E, 'Counter Value Register 2'),
+    'ETMCNTVR3': (0x05F, 'Counter Value Register 3'),
+
+    'ETMSQabEVR0': (0x060, 'Sequencer State Transition Event Register 0'),
+    'ETMSQabEVR1': (0x061, 'Sequencer State Transition Event Register 1'),
+    'ETMSQabEVR2': (0x062, 'Sequencer State Transition Event Register 2'),
+    'ETMSQabEVR3': (0x063, 'Sequencer State Transition Event Register 3'),
+    'ETMSQabEVR4': (0x064, 'Sequencer State Transition Event Register 4'),
+    'ETMSQabEVR5': (0x065, 'Sequencer State Transition Event Register 5'),
+
+    'ETMSQR': (0x067, 'Current Sequencer State Register'),
+
+    'ETMEXTOUTEVR0': (0x068, 'External Output Event Registers 0'),
+    'ETMEXTOUTEVR1': (0x069, 'External Output Event Registers 1'),
+    'ETMEXTOUTEVR2': (0x06A, 'External Output Event Registers 2'),
+    'ETMEXTOUTEVR3': (0x06B, 'External Output Event Registers 3'),
+
+    'ETMCIDCVR0': (0x06C, 'Context ID Comparator Value Register 0'),
+    'ETMCIDCVR1': (0x06D, 'Context ID Comparator Value Register 1'),
+    'ETMCIDCVR2': (0x06E, 'Context ID Comparator Value Register 2'),
+
+    'ETMCIDCMR0': (0x06F, 'Context ID Mask Register'),
+
+    'ETMIMPSPEC0': (0x070, 'Implementation Specific Register 0'),
+    'ETMIMPSPEC1': (0x071, 'Implementation Specific Register 1'),
+    'ETMIMPSPEC2': (0x072, 'Implementation Specific Register 2'),
+    'ETMIMPSPEC3': (0x073, 'Implementation Specific Register 3'),
+    'ETMIMPSPEC4': (0x074, 'Implementation Specific Register 4'),
+    'ETMIMPSPEC5': (0x075, 'Implementation Specific Register 5'),
+    'ETMIMPSPEC6': (0x076, 'Implementation Specific Register 6'),
+    'ETMIMPSPEC7': (0x077, 'Implementation Specific Register 7'),
+
+    'ETMSYNCFR': (0x078, 'Synchronization Frequency Register'),
+    'ETMIDR': (0x079, 'ID register'),
+    'ETMCCER': (0x07A, 'Configuration Code Extension Register'),
+    'ETMEXTINSELR': (0x07B, 'Extended External Input Selection Register'),
+    'ETMTESSEICR': (0x07C, 'TraceEnable Start/Stop EmbeddedICE Control Register'),
+    'ETMEIBCR': (0x07D, 'EmbeddedICE Behavior COntrol Register'),
+    'ETMTSEVR': (0x07E, 'Timestamp Event Register'),
+    'ETMAUXCR': (0x07F, 'Auxilary Control Register'),
+    'ETMTRACEIDR': (0x080, 'CoreSight Trace ID Register'),
+    'ETMVMIDCVR': (0x090, 'VMID Comparator Value Register'),
+
+    'ETMOSLAR': (0x0C0, 'OS Lock Access Register'),
+    'ETMOSLSR': (0x0C1, 'OS Lock Status Register'),
+    'ETMPDCR': (0x0C4, 'Device Power-DOwn Control Register'),
+    'ETMPDSR': (0x0C5, 'Device Power Down Status Register'),
+
+    'ETMITCTRL': (0x3C0, 'Integration Mode Control Register'),
+    'ETMCLAIMSET': (0x3E8, 'Claim Tag Set Register'),
+    'ETMCLAIMCLR': (0x3E9, 'Claim Tag Clear Register'),
+    'ETMLAR': (0x3Ec, 'Lock Access Register'),
+    'ETMLSR': (0x3ED, 'Lock Status Register'),
+    'ETMAUTHSTATUS': (0x3EE, 'Authentication Status Register'),
+    'ETMDEVID': (0x3F2, 'Device Configuration Register'),
+    'ETMDEVTYPE': (0x3F3, 'Device Type Register'),
+    'ETMPIDR4': (0x3F4, 'Peripheral ID4 Register'),
+    'ETMPIDR0': (0x3F8, 'Peripheral ID0 Register'),
+    'ETMPIDR1': (0x3F9, 'Peripheral ID1 Register'),
+    'ETMPIDR2': (0x3FA, 'Peripheral ID2 Register'),
+    'ETMPIDR3': (0x3FB, 'Peripheral ID3 Register'),
+    'ETMCIDR0': (0x3FC, 'Component ID0 Register'),
+    'ETMCIDR1': (0x3FD, 'Component ID1 Register'),
+    'ETMCIDR2': (0x3FE, 'Component ID2 Register'),
+}
+
+
+class QDSSDump():
+
+    def __init__(self):
+        self.tmc_etr_start = None
+        self.etf_start = None
+        self.tmc_etf_start = None
+        self.etm_regs0 = None
+        self.etm_regs1 = None
+        self.etm_regs2 = None
+        self.etm_regs3 = None
+
+    # Assumptions: Any address given here has been checked for correct magic
+    def print_tmc_etf(self, ram_dump):
+        if self.tmc_etf_start is None:
+            print_out_str(
+                "!!! TMC-ETF address has not been set! I can't continue!")
+            return
+
+        print_out_str('Now printing TMC-ETF registers to file')
+        tmc_etf_out = ram_dump.open_file('tmc_etf.txt')
+        for a, b in tmc_registers.iteritems():
+            offset, name = b
+            tmc_etf_out.write('{0} ({1}): {2:x}\n'.format(
+                a, name, ram_dump.read_word(self.tmc_etf_start + offset, False)))
+        tmc_etf_out.close()
+
+    def print_tmc_etr(self, ram_dump):
+        if self.tmc_etr_start is None:
+            print_out_str(
+                "!!! TMC-ETR address has not been set! I can't continue!")
+            return
+
+        print_out_str('Now printing TMC-ETR registers to file')
+        tmc_etf_out = ram_dump.open_file('tmc_etr.txt')
+        for a, b in tmc_registers.iteritems():
+            offset, name = b
+            tmc_etf_out.write('{0} ({1}): {2:x}\n'.format(
+                a, name, ram_dump.read_word(self.tmc_etr_start + offset, False)))
+        tmc_etf_out.close()
+
+    def print_etm_registers(self, ram_dump, base, fname):
+        etm_out = ram_dump.open_file(fname)
+        for a, b in etm_registers.iteritems():
+            offset, name = b
+            etm_out.write('{0} ({1}): {2:x})\n'.format(
+                a, name, ram_dump.read_word(base + offset * 4, False)))
+        etm_out.close()
+
+    def print_all_etm_register(self, ram_dump):
+        if self.etm_regs0 is None:
+            print_out_str(
+                '!!! ETM REGS 0 address was not set! Nothing will be parsed')
+        else:
+            self.print_etm_registers(ram_dump, self.etm_regs0, 'etm_regs0')
+
+        if self.etm_regs1 is None:
+            print_out_str(
+                '!!! ETM REGS 1 address was not set! Nothing will be parsed')
+        else:
+            self.print_etm_registers(ram_dump, self.etm_regs1, 'etm_regs1')
+
+        if self.etm_regs2 is None:
+            print_out_str(
+                '!!! ETM REGS 2 address was not set! Nothing will be parsed')
+        else:
+            self.print_etm_registers(ram_dump, self.etm_regs2, 'etm_regs2')
+
+        if self.etm_regs3 is None:
+            print_out_str(
+                '!!! ETM REGS 3 address was not set! Nothing will be parsed')
+        else:
+            self.print_etm_registers(ram_dump, self.etm_regs3, 'etm_regs3')
+
+    def save_etf_bin(self, ram_dump):
+        tmc_etf = ram_dump.open_file('tmc-etf.bin')
+        if self.tmc_etf_start is None or self.etf_start is None:
+            print_out_str('!!! ETF was not the current sink!')
+            tmc_etf.close()
+            return
+
+        ctl_offset, ctl_desc = tmc_registers['CTL']
+        mode_offset, mode_desc = tmc_registers['MODE']
+
+        ctl = ram_dump.read_word(self.tmc_etf_start + ctl_offset, False)
+        mode = ram_dump.read_word(self.tmc_etf_start + mode_offset, False)
+
+        if (ctl & 0x1) == 1 and (mode == 0):
+            # Save the 64kb of data
+            for i in range(0, 64 * 1024):
+                val = ram_dump.read_byte(self.etf_start + i, False)
+                tmc_etf.write(struct.pack('<B', val))
+        else:
+            print_out_str('!!! ETF was not the current sink!')
+
+        tmc_etf.close()
+
+    def save_etr_bin(self, ram_dump):
+        tmc_etr = ram_dump.open_file('tmc-etr.bin')
+        if self.tmc_etr_start is None:
+            print_out_str('!!! ETR was not enabled!')
+            tmc_etr.close()
+            return
+
+        ctl_offset, ctl_desc = tmc_registers['CTL']
+        mode_offset, mode_desc = tmc_registers['MODE']
+
+        ctl = ram_dump.read_word(self.tmc_etr_start + ctl_offset, False)
+        mode = ram_dump.read_word(self.tmc_etr_start + mode_offset, False)
+
+        if (ctl & 0x1) == 1 and (mode == 0):
+            sts_offset, sts_desc = tmc_registers['STS']
+            sts = ram_dump.read_word(self.tmc_etr_start + sts_offset, False)
+
+            dbalo_offset, dbalo_desc = tmc_registers['DBALO']
+            dbalo = ram_dump.read_word(
+                self.tmc_etr_start + dbalo_offset, False)
+
+            rsz_offset, rsz_desc = tmc_registers['RSZ']
+            rsz = ram_dump.read_word(self.tmc_etr_start + rsz_offset, False)
+            # rsz is given in words so convert to bytes
+            rsz = 4 * rsz
+
+            rwp_offset, rwp_desc = tmc_registers['RWP']
+            rwp = ram_dump.read_word(self.tmc_etr_start + rwp_offset, False)
+
+            if (sts & 0x1) == 1:
+                for i in range(rwp, dbalo + rsz):
+                    val = ram_dump.read_byte(i, False)
+                    tmc_etr.write(struct.pack('<B', val))
+
+                for i in range(dbalo, rwp):
+                    val = ram_dump.read_byte(i, False)
+                    tmc_etr.write(struct.pack('<B', val))
+
+            else:
+                for i in range(dbalo, dbalo + rsz):
+                    val = ram_dump.read_byte(i, False)
+                    tmc_etr.write(struct.pack('<B', val))
+        else:
+            print_out_str('!!! ETR was not the current sink!')
+
+        tmc_etr.close()
+
+    def dump_all(self, ram_dump):
+        self.print_tmc_etf(ram_dump)
+        self.print_tmc_etr(ram_dump)
+        self.print_all_etm_register(ram_dump)
+        self.save_etf_bin(ram_dump)
+        self.save_etr_bin(ram_dump)
diff --git a/linux-ramdump-parser-v2/ramdump.py b/linux-ramdump-parser-v2/ramdump.py
new file mode 100644
index 0000000000000000000000000000000000000000..bedd21f1bd50034b52f9a460b87846786cd4f8b8
--- /dev/null
+++ b/linux-ramdump-parser-v2/ramdump.py
@@ -0,0 +1,1304 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import sys
+import re
+import os
+import struct
+import gzip
+import functools
+from tempfile import NamedTemporaryFile
+
+import gdbmi
+from print_out import print_out_str
+from mmu import Armv7MMU, Armv7LPAEMMU
+
+FP = 11
+SP = 13
+LR = 14
+PC = 15
+THREAD_SIZE = 8192
+
+HARDWARE_ID_IDX = 0
+MEMORY_START_IDX = 1
+PHYS_OFFSET_IDX = 2
+WATCHDOG_BARK_OFFSET_IDX = 3
+IMEM_START_IDX = 4
+CPU_TYPE = 5
+IMEM_FILENAME = 6
+VERSION_COMPARE = 7
+
+smem_offsets = [
+    0,  # 8960/9x15 family and earlier
+    0x0FA00000,  # 8974
+    0x00100000,
+    0x0D900000,  # 8610
+    0x01100000,  # 9635
+]
+
+hw_ids = [
+    (8660, 0x40000000, 0x40200000, 0x2a05f658,
+     0x2a05f000, 'SCORPION', 'IMEM_C.BIN', None),
+    (8960, 0x80000000, 0x80200000, 0x2a03f658,
+     0x2a03f000, 'KRAIT',    'IMEM_C.BIN', None),
+    (8064, 0x80000000, 0x80200000, 0x2a03f658,
+     0x2a03f000, 'KRAIT',    'IMEM_C.BIN', None),
+    (9615, 0x40000000, 0x40800000, 0x0,
+     0x0,        'CORTEXA5', None,         None),
+    (8974, 0x0,        0x0,        0xfe805658,
+     0xfe800000, 'KRAIT',    'OCIMEM.BIN', None),
+    (9625, 0x0,        0x00200000, 0xfc42b658,
+     0xfc428000, 'CORTEXA5', 'MSGRAM.BIN', 1),
+    (9625, 0x0,        0x00200000, 0xfe805658,
+     0xfe800000, 'CORTEXA5', 'OCIMEM.BIN', 2),
+    (8625, 0x0,        0x00200000, 0x0,
+     0x0,        'SCORPION',  None,        None),
+    (8226, 0x0,        0x00000000, 0xfe805658,
+     0xfe800000, 'CORTEXA7', 'OCIMEM.BIN', None),
+    (8610, 0x0,        0x00000000, 0xfe805658,
+     0xfe800000, 'CORTEXA7', 'OCIMEM.BIN', None),
+    (8084, 0x0,        0x0,        0xfe805658,
+     0xfe800000, 'KRAIT',    'OCIMEM.BIN', None),
+    (9635, 0x0,        0x00000000, 0xfe805658,
+     0xfe800000, 'CORTEXA7', 'OCIMEM.BIN', None),
+    (8092, 0x0,        0x0,        0xfe805658,
+     0xfe800000, 'KRAIT',    'OCIMEM.BIN', None),
+]
+
+MSM_CPU_UNKNOWN = 0
+MSM_CPU_7X01 = -1
+MSM_CPU_7X25 = -1
+MSM_CPU_7X27 = -1
+MSM_CPU_8X50 = -1
+MSM_CPU_8X50A = -1
+MSM_CPU_7X30 = -1
+MSM_CPU_8X55 = -1
+MSM_CPU_8X60 = 8660
+MSM_CPU_8960 = 8960
+MSM_CPU_8960AB = 8960
+MSM_CPU_7X27A = 8625
+FSM_CPU_9XXX = -1
+MSM_CPU_7X25A = 8625
+MSM_CPU_7X25AA = 8625
+MSM_CPU_7X25AB = 8625
+MSM_CPU_8064 = 8064
+MSM_CPU_8064AB = 8064
+MSM_CPU_8930 = 8960
+MSM_CPU_8930AA = 8960
+MSM_CPU_8930AB = 8960
+MSM_CPU_7X27AA = -1
+MSM_CPU_9615 = 9615
+MSM_CPU_8974 = 8974
+MSM_CPU_8974PRO_AA = 8974
+MSM_CPU_8974PRO_AB = 8974
+MSM_CPU_8974PRO_AC = 8974
+MSM_CPU_8627 = 8960
+MSM_CPU_8625 = 9615
+MSM_CPU_9625 = 9625
+MSM_CPU_8226 = 8226
+MSM_CPU_8610 = 8610
+MSM_CPU_8084 = 8084
+MSM_CPU_KRYPTON = 9635
+MSM_CPU_8092 = 8092
+
+    # id, cpu, cpuname
+cpu_of_id = [
+    # 7x01 IDs
+    (1,  MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (16, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (17, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (18, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (19, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (23, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (25, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (26, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (32, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (33, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (34, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+    (35, MSM_CPU_7X01, 'MSM_CPU_7X01'),
+
+    # 7x25 IDs
+    (20, MSM_CPU_7X25, 'MSM_CPU_7X25'),
+    (21, MSM_CPU_7X25, 'MSM_CPU_7X25'),  # 7225
+    (24, MSM_CPU_7X25, 'MSM_CPU_7X25'),  # 7525
+    (27, MSM_CPU_7X25, 'MSM_CPU_7X25'),  # 7625
+    (39, MSM_CPU_7X25, 'MSM_CPU_7X25'),
+    (40, MSM_CPU_7X25, 'MSM_CPU_7X25'),
+    (41, MSM_CPU_7X25, 'MSM_CPU_7X25'),
+    (42, MSM_CPU_7X25, 'MSM_CPU_7X25'),
+    (62, MSM_CPU_7X25, 'MSM_CPU_7X25'),  # 7625-1
+    (63, MSM_CPU_7X25, 'MSM_CPU_7X25'),  # 7225-1
+    (66, MSM_CPU_7X25, 'MSM_CPU_7X25'),  # 7225-2
+
+
+    # 7x27 IDs
+    (43, MSM_CPU_7X27, 'MSM_CPU_7X27'),
+    (44, MSM_CPU_7X27, 'MSM_CPU_7X27'),
+    (61, MSM_CPU_7X27, 'MSM_CPU_7X27'),
+    (67, MSM_CPU_7X27, 'MSM_CPU_7X27'),  # 7227-1
+    (68, MSM_CPU_7X27, 'MSM_CPU_7X27'),  # 7627-1
+    (69, MSM_CPU_7X27, 'MSM_CPU_7X27'),  # 7627-2
+
+
+    # 8x50 IDs
+    (30, MSM_CPU_8X50, 'MSM_CPU_8X50'),
+    (36, MSM_CPU_8X50, 'MSM_CPU_8X50'),
+    (37, MSM_CPU_8X50, 'MSM_CPU_8X50'),
+    (38, MSM_CPU_8X50, 'MSM_CPU_8X50'),
+
+    # 7x30 IDs
+    (59, MSM_CPU_7X30, 'MSM_CPU_7X30'),
+    (60, MSM_CPU_7X30, 'MSM_CPU_7X30'),
+
+    # 8x55 IDs
+    (74, MSM_CPU_8X55, 'MSM_CPU_8X55'),
+    (75, MSM_CPU_8X55, 'MSM_CPU_8X55'),
+    (85, MSM_CPU_8X55, 'MSM_CPU_8X55'),
+
+    # 8x60 IDs
+    (70, MSM_CPU_8X60, 'MSM_CPU_8X60'),
+    (71, MSM_CPU_8X60, 'MSM_CPU_8X60'),
+    (86, MSM_CPU_8X60, 'MSM_CPU_8X60'),
+
+    # 8960 IDs
+    (87, MSM_CPU_8960, 'MSM_CPU_8960'),
+
+    # 7x25A IDs
+    (88, MSM_CPU_7X25A, 'MSM_CPU_7X25A'),
+    (89, MSM_CPU_7X25A, 'MSM_CPU_7X25A'),
+    (96, MSM_CPU_7X25A, 'MSM_CPU_7X25A'),
+
+    # 7x27A IDs
+    (90, MSM_CPU_7X27A, 'MSM_CPU_7X27A'),
+    (91, MSM_CPU_7X27A, 'MSM_CPU_7X27A'),
+    (92, MSM_CPU_7X27A, 'MSM_CPU_7X27A'),
+    (97, MSM_CPU_7X27A, 'MSM_CPU_7X27A'),
+
+    # FSM9xxx ID
+    (94, FSM_CPU_9XXX, 'FSM_CPU_9XXX'),
+    (95, FSM_CPU_9XXX, 'FSM_CPU_9XXX'),
+
+    #  7x25AA ID
+    (98, MSM_CPU_7X25AA, 'MSM_CPU_7X25AA'),
+    (99, MSM_CPU_7X25AA, 'MSM_CPU_7X25AA'),
+    (100, MSM_CPU_7X25AA, 'MSM_CPU_7X25AA'),
+
+    #  7x27AA ID
+    (101, MSM_CPU_7X27AA, 'MSM_CPU_7X27AA'),
+    (102, MSM_CPU_7X27AA, 'MSM_CPU_7X27AA'),
+    (103, MSM_CPU_7X27AA, 'MSM_CPU_7X27AA'),
+
+    # 9x15 ID
+    (104, MSM_CPU_9615, 'MSM_CPU_9615'),
+    (105, MSM_CPU_9615, 'MSM_CPU_9615'),
+    (106, MSM_CPU_9615, 'MSM_CPU_9615'),
+    (107, MSM_CPU_9615, 'MSM_CPU_9615'),
+
+    # 8064 IDs
+    (109, MSM_CPU_8064, 'MSM_CPU_8064'),
+    (130, MSM_CPU_8064, 'MSM_CPU_8064'),
+
+    # 8930 IDs
+    (116, MSM_CPU_8930, 'MSM_CPU_8930'),
+    (117, MSM_CPU_8930, 'MSM_CPU_8930'),
+    (118, MSM_CPU_8930, 'MSM_CPU_8930'),
+    (119, MSM_CPU_8930, 'MSM_CPU_8930'),
+
+    # 8627 IDs
+    (120, MSM_CPU_8627, 'MSM_CPU_8627'),
+    (121, MSM_CPU_8627, 'MSM_CPU_8627'),
+
+    # 8660A ID
+    (122, MSM_CPU_8960, 'MSM_CPU_8960'),
+
+    # 8260A ID
+    (123, MSM_CPU_8960, '8260A'),
+
+    # 8060A ID
+    (124, MSM_CPU_8960, '8060A'),
+
+    # Copper IDs
+    (126, MSM_CPU_8974, 'MSM_CPU_8974'),
+    (184, MSM_CPU_8974, 'MSM_CPU_8974'),
+    (185, MSM_CPU_8974, 'MSM_CPU_8974'),
+    (186, MSM_CPU_8974, 'MSM_CPU_8974'),
+
+    # 8974 PRO AA IDs
+    (208, MSM_CPU_8974PRO_AA, 'MSM_CPU_8974PRO_AA'),
+    (211, MSM_CPU_8974PRO_AA, 'MSM_CPU_8974PRO_AA'),
+    (214, MSM_CPU_8974PRO_AA, 'MSM_CPU_8974PRO_AA'),
+    (217, MSM_CPU_8974PRO_AA, 'MSM_CPU_8974PRO_AA'),
+
+    # 8974 PRO AB IDs
+    (209, MSM_CPU_8974PRO_AB, 'MSM_CPU_8974PRO_AB'),
+    (212, MSM_CPU_8974PRO_AB, 'MSM_CPU_8974PRO_AB'),
+    (215, MSM_CPU_8974PRO_AB, 'MSM_CPU_8974PRO_AB'),
+    (218, MSM_CPU_8974PRO_AB, 'MSM_CPU_8974PRO_AB'),
+
+    # 8974 PRO AC IDs
+    (194, MSM_CPU_8974PRO_AC, 'MSM_CPU_8974PRO_AC'),
+    (210, MSM_CPU_8974PRO_AC, 'MSM_CPU_8974PRO_AC'),
+    (213, MSM_CPU_8974PRO_AC, 'MSM_CPU_8974PRO_AC'),
+    (216, MSM_CPU_8974PRO_AC, 'MSM_CPU_8974PRO_AC'),
+
+    # 8625 IDs
+    (127, MSM_CPU_8625, 'MSM_CPU_8625'),
+    (128, MSM_CPU_8625, 'MSM_CPU_8625'),
+    (129, MSM_CPU_8625, 'MSM_CPU_8625'),
+
+    # 8064 MPQ ID */
+    (130, MSM_CPU_8064, 'MSM_CPU_8064'),
+
+    # 7x25AB IDs
+    (131, MSM_CPU_7X25AB, 'MSM_CPU_7X25AB'),
+    (132, MSM_CPU_7X25AB, 'MSM_CPU_7X25AB'),
+    (133, MSM_CPU_7X25AB, 'MSM_CPU_7X25AB'),
+    (135, MSM_CPU_7X25AB, 'MSM_CPU_7X25AB'),
+
+    # 9625 IDs
+    (134, MSM_CPU_9625, 'MSM_CPU_9625'),
+    (148, MSM_CPU_9625, 'MSM_CPU_9625'),
+    (149, MSM_CPU_9625, 'MSM_CPU_9625'),
+    (150, MSM_CPU_9625, 'MSM_CPU_9625'),
+    (151, MSM_CPU_9625, 'MSM_CPU_9625'),
+    (152, MSM_CPU_9625, 'MSM_CPU_9625'),
+    (173, MSM_CPU_9625, 'MSM_CPU_9625'),
+    (174, MSM_CPU_9625, 'MSM_CPU_9625'),
+    (175, MSM_CPU_9625, 'MSM_CPU_9625'),
+
+    # 8960AB IDs
+    (138, MSM_CPU_8960AB, 'MSM_CPU_8960AB'),
+    (139, MSM_CPU_8960AB, 'MSM_CPU_8960AB'),
+    (140, MSM_CPU_8960AB, 'MSM_CPU_8960AB'),
+    (141, MSM_CPU_8960AB, 'MSM_CPU_8960AB'),
+
+    # 8930AA IDs
+    (142, MSM_CPU_8930AA, 'MSM_CPU_8930AA'),
+    (143, MSM_CPU_8930AA, 'MSM_CPU_8930AA'),
+    (144, MSM_CPU_8930AA, 'MSM_CPU_8930AA'),
+
+    # 8226 IDx
+    (145, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (158, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (159, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (198, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (199, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (200, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (205, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (219, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (220, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (221, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (222, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (223, MSM_CPU_8226, 'MSM_CPU_8226'),
+    (224, MSM_CPU_8226, 'MSM_CPU_8226'),
+
+    # 8610 IDx
+    (147, MSM_CPU_8610, 'MSM_CPU_8610'),
+    (161, MSM_CPU_8610, 'MSM_CPU_8610'),
+    (162, MSM_CPU_8610, 'MSM_CPU_8610'),
+    (163, MSM_CPU_8610, 'MSM_CPU_8610'),
+    (164, MSM_CPU_8610, 'MSM_CPU_8610'),
+    (165, MSM_CPU_8610, 'MSM_CPU_8610'),
+    (166, MSM_CPU_8610, 'MSM_CPU_8610'),
+
+    # 8064AB IDs
+    (153, MSM_CPU_8064AB, 'MSM_CPU_8064AB'),
+
+    # 8930AB IDs
+    (154, MSM_CPU_8930AB, 'MSM_CPU_8930AB'),
+    (155, MSM_CPU_8930AB, 'MSM_CPU_8930AB'),
+    (156, MSM_CPU_8930AB, 'MSM_CPU_8930AB'),
+    (157, MSM_CPU_8930AB, 'MSM_CPU_8930AB'),
+
+    (160, MSM_CPU_8930AA, 'MSM_CPU_8930AA'),
+
+    # 8084 IDs
+    (178, MSM_CPU_8084, 'MSM_CPU_8084'),
+
+    # 9635 IDs
+    (187, MSM_CPU_KRYPTON, 'MSM_CPU_KRYPTON'),
+    (227, MSM_CPU_KRYPTON, 'MSM_CPU_KRYPTON'),
+    (228, MSM_CPU_KRYPTON, 'MSM_CPU_KRYPTON'),
+    (229, MSM_CPU_KRYPTON, 'MSM_CPU_KRYPTON'),
+    (230, MSM_CPU_KRYPTON, 'MSM_CPU_KRYPTON'),
+    (231, MSM_CPU_KRYPTON, 'MSM_CPU_KRYPTON'),
+
+    (146, MSM_CPU_8092, 'MSM_CPU_8092'),
+
+    # Uninitialized IDs are not known to run Linux.
+    # MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
+    # considered as unknown CPU.
+]
+
+socinfo_v1 = functools.reduce(lambda x, y: x + y, [
+    'I',  # format
+    'I',  # id
+    'I',  # version
+])
+
+launch_config_str = 'OS=\nID=T32_1000002\nTMP=C:\\TEMP\nSYS=C:\\T32\nHELP=C:\\T32\\pdf\n\nPBI=SIM\nSCREEN=\nFONT=SMALL\nHEADER=Trace32-ScorpionSimulator\nPRINTER=WINDOWS'
+
+# The smem code is very stable and unlikely to go away or be changed.
+# Rather than go through the hassel of parsing the id through gdb,
+# just hard code it
+
+SMEM_HW_SW_BUILD_ID = 0x89
+BUILD_ID_LENGTH = 32
+
+first_mem_file_names = ['EBICS0.BIN',
+                        'EBI1.BIN', 'DDRCS0.BIN', 'ebi1_cs0.bin', 'DDRCS0_0.BIN']
+extra_mem_file_names = ['EBI1CS1.BIN', 'DDRCS1.BIN', 'ebi1_cs1.bin', 'DDRCS0_1.BIN']
+
+
+class RamDump():
+
+    class Unwinder ():
+
+        class Stackframe ():
+
+            def __init__(self, fp, sp, lr, pc):
+                self.fp = fp
+                self.sp = sp
+                self.lr = lr
+                self.pc = pc
+
+        class UnwindCtrlBlock ():
+
+            def __init__(self):
+                self.vrs = 16 * [0]
+                self.insn = 0
+                self.entries = -1
+                self.byte = -1
+                self.index = 0
+
+        def __init__(self, ramdump):
+            start = ramdump.addr_lookup('__start_unwind_idx')
+            end = ramdump.addr_lookup('__stop_unwind_idx')
+            if (start is None) or (end is None):
+                print_out_str('!!! Could not lookup unwinding information')
+                return None
+            # addresses
+            self.start_idx = start
+            self.stop_idx = end
+            self.unwind_table = []
+            self.ramdump = ramdump
+            i = 0
+            for addr in range(start, end, 8):
+                (a, b) = ramdump.read_string(addr, '<II')
+                self.unwind_table.append((a, b, start + 8 * i))
+                i += 1
+
+            ver = ramdump.version
+            if re.search('3.0.\d', ver) is not None:
+                self.search_idx = self.search_idx_3_0
+            else:
+                self.search_idx = self.search_idx_3_4
+                # index into the table
+                self.origin = self.unwind_find_origin()
+
+        def unwind_find_origin(self):
+            start = 0
+            stop = len(self.unwind_table)
+            while (start < stop):
+                mid = start + ((stop - start) >> 1)
+                if (self.unwind_table[mid][0] >= 0x40000000):
+                    start = mid + 1
+                else:
+                    stop = mid
+            return stop
+
+        def unwind_frame_generic(self, frame):
+            high = 0
+            fp = frame.fp
+
+            low = frame.sp
+            mask = (THREAD_SIZE) - 1
+
+            high = (low + mask) & (~mask)  # ALIGN(low, THREAD_SIZE)
+
+            # /* check current frame pointer is within bounds */
+            if (fp < (low + 12) or fp + 4 >= high):
+                return -1
+
+            fp_is_at = self.ramdump.read_word(frame.fp - 12)
+            sp_is_at = self.ramdump.read_word(frame.fp - 8)
+            pc_is_at = self.ramdump.read_word(frame.fp - 4)
+
+            frame.fp = fp_is_at
+            frame.sp = sp_is_at
+            frame.pc = pc_is_at
+
+            return 0
+
+        def walk_stackframe_generic(self, frame):
+            while True:
+                symname = self.ramdump.addr_to_symbol(frame.pc)
+                print_out_str(symname)
+
+                ret = self.unwind_frame_generic(frame)
+                if ret < 0:
+                    break
+
+        def unwind_backtrace_generic(self, sp, fp, pc):
+            frame = self.Stackframe()
+            frame.fp = fp
+            frame.pc = pc
+            frame.sp = sp
+            walk_stackframe_generic(frame)
+
+        def search_idx_3_4(self, addr):
+            start = 0
+            stop = len(self.unwind_table)
+            orig = addr
+
+            if (addr < self.start_idx):
+                stop = self.origin
+            else:
+                start = self.origin
+
+            if (start >= stop):
+                return None
+
+            addr = (addr - self.unwind_table[start][2]) & 0x7fffffff
+
+            while (start < (stop - 1)):
+                mid = start + ((stop - start) >> 1)
+
+                dif = (self.unwind_table[mid][2]
+                       - self.unwind_table[start][2])
+                if ((addr - dif) < self.unwind_table[mid][0]):
+                    stop = mid
+                else:
+                    addr = addr - dif
+                    start = mid
+
+            if self.unwind_table[start][0] <= addr:
+                return self.unwind_table[start]
+            else:
+                return None
+
+        def search_idx_3_0(self, addr):
+            first = 0
+            last = len(self.unwind_table)
+            while (first < last - 1):
+                mid = first + ((last - first + 1) >> 1)
+                if (addr < self.unwind_table[mid][0]):
+                    last = mid
+                else:
+                    first = mid
+
+            return self.unwind_table[first]
+
+        def unwind_get_byte(self, ctrl):
+
+            if (ctrl.entries <= 0):
+                print_out_str('unwind: Corrupt unwind table')
+                return 0
+
+            val = self.ramdump.read_word(ctrl.insn)
+
+            ret = (val >> (ctrl.byte * 8)) & 0xff
+
+            if (ctrl.byte == 0):
+                ctrl.insn += 4
+                ctrl.entries -= 1
+                ctrl.byte = 3
+            else:
+                ctrl.byte -= 1
+
+            return ret
+
+        def unwind_exec_insn(self, ctrl, trace=False):
+            insn = self.unwind_get_byte(ctrl)
+
+            if ((insn & 0xc0) == 0x00):
+                ctrl.vrs[SP] += ((insn & 0x3f) << 2) + 4
+                if trace:
+                    print_out_str(
+                        '    add {0} to stack'.format(((insn & 0x3f) << 2) + 4))
+            elif ((insn & 0xc0) == 0x40):
+                ctrl.vrs[SP] -= ((insn & 0x3f) << 2) + 4
+                if trace:
+                    print_out_str(
+                        '    subtract {0} from stack'.format(((insn & 0x3f) << 2) + 4))
+            elif ((insn & 0xf0) == 0x80):
+                vsp = ctrl.vrs[SP]
+                reg = 4
+
+                insn = (insn << 8) | self.unwind_get_byte(ctrl)
+                mask = insn & 0x0fff
+                if (mask == 0):
+                    print_out_str("unwind: 'Refuse to unwind' instruction")
+                    return -1
+
+                # pop R4-R15 according to mask */
+                load_sp = mask & (1 << (13 - 4))
+                while (mask):
+                    if (mask & 1):
+                        ctrl.vrs[reg] = self.ramdump.read_word(vsp)
+                        if trace:
+                            print_out_str(
+                                '    pop r{0} from stack'.format(reg))
+                        if ctrl.vrs[reg] is None:
+                            return -1
+                        vsp += 4
+                    mask >>= 1
+                    reg += 1
+                if not load_sp:
+                    ctrl.vrs[SP] = vsp
+
+            elif ((insn & 0xf0) == 0x90 and (insn & 0x0d) != 0x0d):
+                if trace:
+                    print_out_str(
+                        '    set SP with the value from {0}'.format(insn & 0x0f))
+                ctrl.vrs[SP] = ctrl.vrs[insn & 0x0f]
+            elif ((insn & 0xf0) == 0xa0):
+                vsp = ctrl.vrs[SP]
+                a = list(range(4, 4 + (insn & 7)))
+                a.append(4 + (insn & 7))
+                # pop R4-R[4+bbb] */
+                for reg in (a):
+                    ctrl.vrs[reg] = self.ramdump.read_word(vsp)
+                    if trace:
+                        print_out_str('    pop r{0} from stack'.format(reg))
+
+                    if ctrl.vrs[reg] is None:
+                        return -1
+                    vsp += 4
+                if (insn & 0x80):
+                    if trace:
+                        print_out_str('    set LR from the stack')
+                    ctrl.vrs[14] = self.ramdump.read_word(vsp)
+                    if ctrl.vrs[14] is None:
+                        return -1
+                    vsp += 4
+                ctrl.vrs[SP] = vsp
+            elif (insn == 0xb0):
+                if trace:
+                    print_out_str('    set pc = lr')
+                if (ctrl.vrs[PC] == 0):
+                    ctrl.vrs[PC] = ctrl.vrs[LR]
+                ctrl.entries = 0
+            elif (insn == 0xb1):
+                mask = self.unwind_get_byte(ctrl)
+                vsp = ctrl.vrs[SP]
+                reg = 0
+
+                if (mask == 0 or mask & 0xf0):
+                    print_out_str('unwind: Spare encoding')
+                    return -1
+
+                # pop R0-R3 according to mask
+                while mask:
+                    if (mask & 1):
+                        ctrl.vrs[reg] = self.ramdump.read_word(vsp)
+                        if trace:
+                            print_out_str(
+                                '    pop r{0} from stack'.format(reg))
+                        if ctrl.vrs[reg] is None:
+                            return -1
+                        vsp += 4
+                    mask >>= 1
+                    reg += 1
+                ctrl.vrs[SP] = vsp
+            elif (insn == 0xb2):
+                uleb128 = self.unwind_get_byte(ctrl)
+                if trace:
+                    print_out_str(
+                        '    Adjust sp by {0}'.format(0x204 + (uleb128 << 2)))
+
+                ctrl.vrs[SP] += 0x204 + (uleb128 << 2)
+            else:
+                print_out_str('unwind: Unhandled instruction')
+                return -1
+
+            return 0
+
+        def prel31_to_addr(self, addr):
+            value = self.ramdump.read_word(addr)
+            # offset = (value << 1) >> 1
+            # C wants this sign extended. Python doesn't do that.
+            # Sign extend manually.
+            if (value & 0x40000000):
+                offset = value | 0x80000000
+            else:
+                offset = value
+
+            # This addition relies on integer overflow
+            # Emulate this behavior
+            temp = addr + offset
+            return (temp & 0xffffffff) + ((temp >> 32) & 0xffffffff)
+
+        def unwind_frame(self, frame, trace=False):
+            low = frame.sp
+            high = ((low + (THREAD_SIZE - 1)) & ~(THREAD_SIZE - 1)) + \
+                THREAD_SIZE
+            idx = self.search_idx(frame.pc)
+
+            if (idx is None):
+                if trace:
+                    print_out_str("can't find %x" % frame.pc)
+                return -1
+
+            ctrl = self.UnwindCtrlBlock()
+            ctrl.vrs[FP] = frame.fp
+            ctrl.vrs[SP] = frame.sp
+            ctrl.vrs[LR] = frame.lr
+            ctrl.vrs[PC] = 0
+
+            if (idx[1] == 1):
+                return -1
+
+            elif ((idx[1] & 0x80000000) == 0):
+                ctrl.insn = self.prel31_to_addr(idx[2] + 4)
+
+            elif (idx[1] & 0xff000000) == 0x80000000:
+                ctrl.insn = idx[2] + 4
+            else:
+                print_out_str('not supported')
+                return -1
+
+            val = self.ramdump.read_word(ctrl.insn)
+
+            if ((val & 0xff000000) == 0x80000000):
+                ctrl.byte = 2
+                ctrl.entries = 1
+            elif ((val & 0xff000000) == 0x81000000):
+                ctrl.byte = 1
+                ctrl.entries = 1 + ((val & 0x00ff0000) >> 16)
+            else:
+                return -1
+
+            while (ctrl.entries > 0):
+                urc = self.unwind_exec_insn(ctrl, trace)
+                if (urc < 0):
+                    return urc
+                if (ctrl.vrs[SP] < low or ctrl.vrs[SP] >= high):
+                    return -1
+
+            if (ctrl.vrs[PC] == 0):
+                ctrl.vrs[PC] = ctrl.vrs[LR]
+
+            # check for infinite loop */
+            if (frame.pc == ctrl.vrs[PC]):
+                return -1
+
+            frame.fp = ctrl.vrs[FP]
+            frame.sp = ctrl.vrs[SP]
+            frame.lr = ctrl.vrs[LR]
+            frame.pc = ctrl.vrs[PC]
+
+            return 0
+
+        def unwind_backtrace(self, sp, fp, pc, lr, extra_str='', out_file=None, trace=False):
+            offset = 0
+            frame = self.Stackframe(fp, sp, lr, pc)
+            frame.fp = fp
+            frame.sp = sp
+            frame.lr = lr
+            frame.pc = pc
+
+            while True:
+                where = frame.pc
+                offset = 0
+
+                r = self.ramdump.unwind_lookup(frame.pc)
+                if r is None:
+                    symname = 'UNKNOWN'
+                    offset = 0x0
+                else:
+                    symname, offset = r
+                pstring = (
+                    extra_str + '[<{0:x}>] {1}+0x{2:x}'.format(frame.pc, symname, offset))
+                if out_file:
+                    out_file.write(pstring + '\n')
+                else:
+                    print_out_str(pstring)
+
+                urc = self.unwind_frame(frame, trace)
+                if urc < 0:
+                    break
+
+    def __init__(self, vmlinux_path, nm_path, gdb_path, ebi, file_path, phys_offset, outdir, hw_id=None, hw_version=None):
+        self.ebi_files = []
+        self.phys_offset = None
+        self.tz_start = 0
+        self.ebi_start = 0
+        self.cpu_type = None
+        self.hw_id = hw_id
+        self.hw_version = hw_version
+        self.offset_table = []
+        self.vmlinux = vmlinux_path
+        self.nm_path = nm_path
+        self.gdb_path = gdb_path
+        self.outdir = outdir
+        self.imem_fname = None
+        self.gdbmi = gdbmi.GdbMI(self.gdb_path, self.vmlinux)
+        self.gdbmi.open()
+        if ebi is not None:
+            # TODO sanity check to make sure the memory regions don't overlap
+            for file_path, start, end in ebi:
+                fd = open(file_path, 'rb')
+                if not fd:
+                    print_out_str(
+                        'Could not open {0}. Will not be part of dump'.format(file_path))
+                    continue
+                self.ebi_files.append((fd, start, end, file_path))
+        else:
+            if not self.auto_parse(file_path):
+                return None
+        if self.ebi_start == 0:
+            self.ebi_start = self.ebi_files[0][1]
+        if self.phys_offset is None:
+            self.get_hw_id()
+        if phys_offset is not None:
+            print_out_str(
+                '[!!!] Phys offset was set to {0:x}'.format(phys_offset))
+            self.phys_offset = phys_offset
+        self.lookup_table = []
+        self.page_offset = 0xc0000000
+        self.config = []
+        self.setup_symbol_tables()
+
+        # The address of swapper_pg_dir can be used to determine
+        # whether or not we're running with LPAE enabled since an
+        # extra 4k is needed for LPAE. If it's 0x5000 below
+        # PAGE_OFFSET + TEXT_OFFSET then we know we're using LPAE. For
+        # non-LPAE it should be 0x4000 below PAGE_OFFSET + TEXT_OFFSET
+        swapper_pg_dir_addr = self.addr_lookup('swapper_pg_dir')
+        kernel_text_offset = 0x8000
+        pg_dir_size = kernel_text_offset - \
+            (swapper_pg_dir_addr - self.page_offset)
+        if pg_dir_size == 0x4000:
+            print_out_str('Using non-LPAE MMU')
+            self.mmu = Armv7MMU(self)
+        elif pg_dir_size == 0x5000:
+            print_out_str('Using LPAE MMU')
+            self.mmu = Armv7LPAEMMU(self)
+        else:
+            print_out_str(
+                "!!! Couldn't determine whether or not we're using LPAE!")
+            print_out_str(
+                '!!! This is a BUG in the parser and should be reported.')
+            sys.exit(1)
+
+        if not self.get_version():
+            print_out_str('!!! Could not get the Linux version!')
+            print_out_str(
+                '!!! Your vmlinux is probably wrong for these dumps')
+            print_out_str('!!! Exiting now')
+            sys.exit(1)
+        if not self.get_config():
+            print_out_str('!!! Could not get saved configuration')
+            print_out_str(
+                '!!! This is really bad and probably indicates RAM corruption')
+            print_out_str('!!! Some features may be disabled!')
+        self.unwind = self.Unwinder(self)
+
+    def __del__(self):
+        self.gdbmi.close()
+
+    def open_file(self, file_name, mode='wb'):
+        file_path = os.path.join(self.outdir, file_name)
+        f = None
+        try:
+            f = open(file_path, mode)
+        except:
+            print_out_str('Could not open path {0}'.format(file_path))
+            print_out_str('Do you have write/read permissions on the path?')
+            sys.exit(1)
+        return f
+
+    def get_config(self):
+        kconfig_addr = self.addr_lookup('kernel_config_data')
+        if kconfig_addr is None:
+            return
+        kconfig_size = self.sizeof('kernel_config_data')
+        # size includes magic, offset from it
+        kconfig_size = kconfig_size - 16 - 1
+        zconfig = NamedTemporaryFile(mode='wb', delete=False)
+        # kconfig data starts with magic 8 byte string, go past that
+        s = self.read_cstring(kconfig_addr, 8)
+        if s != 'IKCFG_ST':
+            return
+        kconfig_addr = kconfig_addr + 8
+        for i in range(0, kconfig_size):
+            val = self.read_byte(kconfig_addr + i)
+            zconfig.write(struct.pack('<B', val))
+
+        zconfig.close()
+        zconfig_in = gzip.open(zconfig.name, 'rb')
+        try:
+            t = zconfig_in.readlines()
+        except:
+            return False
+        zconfig_in.close()
+        os.remove(zconfig.name)
+        for l in t:
+            self.config.append(l.rstrip().decode('ascii', 'ignore'))
+        return True
+
+    def is_config_defined(self, config):
+        s = config + '=y'
+        return s in self.config
+
+    def get_version(self):
+        banner_addr = self.addr_lookup('linux_banner')
+        if banner_addr is not None:
+            # Don't try virt to phys yet, compute manually
+            banner_addr = banner_addr - 0xc0000000 + self.phys_offset
+            b = self.read_cstring(banner_addr, 256, False)
+            if b is None:
+                print_out_str('!!! Could not read banner address!')
+                return False
+            v = re.search('Linux version (\d{0,2}\.\d{0,2}\.\d{0,2})', b)
+            if v is None:
+                print_out_str('!!! Could not match version! {0}'.format(b))
+                return False
+            self.version = v.group(1)
+            print_out_str('Linux Banner: ' + b.rstrip())
+            print_out_str('version = {0}'.format(self.version))
+            return True
+        else:
+            print_out_str('!!! Could not lookup banner address')
+            return False
+
+    def print_command_line(self):
+        command_addr = self.addr_lookup('saved_command_line')
+        if command_addr is not None:
+            command_addr = self.read_word(command_addr)
+            b = self.read_cstring(command_addr, 2048)
+            if b is None:
+                print_out_str('!!! could not read saved command line address')
+                return False
+            print_out_str('Command Line: ' + b)
+            return True
+        else:
+            print_out_str('!!! Could not lookup saved command line address')
+            return False
+
+    def auto_parse(self, file_path):
+        first_mem_path = None
+
+        for f in first_mem_file_names:
+            test_path = file_path + '/' + f
+            if os.path.exists(test_path):
+                first_mem_path = test_path
+                break
+
+        if first_mem_path is None:
+            print_out_str('!!! Could not open a memory file. I give up')
+            sys.exit(1)
+
+        first_mem = open(first_mem_path, 'rb')
+        # put some dummy data in for now
+        self.ebi_files = [(first_mem, 0, 0xffff0000, first_mem_path)]
+        if not self.get_hw_id():
+            return False
+        first_mem_end = self.ebi_start + os.path.getsize(first_mem_path) - 1
+        self.ebi_files = [
+            (first_mem, self.ebi_start, first_mem_end, first_mem_path)]
+        print_out_str(
+            'Adding {0} {1:x}--{2:x}'.format(first_mem_path, self.ebi_start, first_mem_end))
+
+        for f in extra_mem_file_names:
+            extra_path = file_path + '/' + f
+
+            if os.path.exists(extra_path):
+                extra = open(extra_path, 'rb')
+                extra_start = self.ebi_start + os.path.getsize(first_mem_path)
+                extra_end = extra_start + os.path.getsize(extra_path) - 1
+                print_out_str(
+                    'Adding {0} {1:x}--{2:x}'.format(extra_path, extra_start, extra_end))
+                self.ebi_files.append(
+                    (extra, extra_start, extra_end, extra_path))
+
+        if self.imem_fname is not None:
+            imemc_path = file_path + '/' + self.imem_fname
+            if os.path.exists(imemc_path):
+                imemc = open(imemc_path, 'rb')
+                imemc_start = self.tz_start
+                imemc_end = imemc_start + os.path.getsize(imemc_path) - 1
+                print_out_str(
+                    'Adding {0} {1:x}--{2:x}'.format(imemc_path, imemc_start, imemc_end))
+                self.ebi_files.append(
+                    (imemc, imemc_start, imemc_end, imemc_path))
+        return True
+
+    # TODO support linux launcher, for when linux T32 actually happens
+    def create_t32_launcher(self):
+        out_path = self.outdir
+        launch_config = open(out_path + '/t32_config.t32', 'wb')
+        launch_config.write(launch_config_str.encode('ascii', 'ignore'))
+        launch_config.close()
+
+        startup_script = open(out_path + '/t32_startup_script.cmm', 'wb')
+
+        startup_script.write(
+            'sys.cpu {0}\n'.format(self.cpu_type).encode('ascii', 'ignore'))
+        startup_script.write('sys.up\n'.encode('ascii', 'ignore'))
+
+        for ram in self.ebi_files:
+            ebi_path = os.path.abspath(ram[3])
+            startup_script.write('data.load.binary {0} 0x{1:x}\n'.format(
+                ebi_path, ram[1]).encode('ascii', 'ignore'))
+        startup_script.write(
+            'PER.S.F C15:0x2 %L 0x{0:x}\n'.format(self.mmu.ttbr).encode('ascii', 'ignore'))
+        if isinstance(self.mmu, Armv7LPAEMMU):
+            # TTBR1. This gets setup once and never change again even if TTBR0
+            # changes
+            startup_script.write('PER.S.F C15:0x102 %L 0x{0:x}\n'.format(
+                self.mmu.ttbr + 0x4000).encode('ascii', 'ignore'))
+            # TTBCR with EAE and T1SZ set approprately
+            startup_script.write(
+                'PER.S.F C15:0x202 %L 0x80030000\n'.encode('ascii', 'ignore'))
+        startup_script.write('mmu.on\n'.encode('ascii', 'ignore'))
+        startup_script.write('mmu.scan\n'.encode('ascii', 'ignore'))
+        startup_script.write(
+            ('data.load.elf ' + os.path.abspath(self.vmlinux) + ' /nocode\n').encode('ascii', 'ignore'))
+        startup_script.write(
+            'task.config c:\\t32\\demo\\arm\\kernel\\linux\\linux.t32\n'.encode('ascii', 'ignore'))
+        startup_script.write(
+            'menu.reprogram c:\\t32\\demo\\arm\\kernel\\linux\\linux.men\n'.encode('ascii', 'ignore'))
+        startup_script.write('task.dtask\n'.encode('ascii', 'ignore'))
+        startup_script.write(
+            'v.v  %ASCII %STRING linux_banner\n'.encode('ascii', 'ignore'))
+        if os.path.exists(out_path + '/regs_panic.cmm'):
+            startup_script.write(
+                'do {0}\n'.format(out_path + '/regs_panic.cmm').encode('ascii', 'ignore'))
+        elif os.path.exists(out_path + '/core0_regs.cmm'):
+            startup_script.write(
+                'do {0}\n'.format(out_path + '/core0_regs.cmm').encode('ascii', 'ignore'))
+        startup_script.close()
+
+        t32_bat = open(out_path + '/launch_t32.bat', 'wb')
+        t32_bat.write(('start c:\\t32\\t32MARM.exe -c ' + out_path + '/t32_config.t32, ' +
+                      out_path + '/t32_startup_script.cmm').encode('ascii', 'ignore'))
+        t32_bat.close()
+        print_out_str(
+            '--- Created a T32 Simulator launcher (run {0}/launch_t32.bat)'.format(out_path))
+
+    def read_tz_offset(self):
+        if self.tz_addr == 0:
+            print_out_str(
+                'No TZ address was given, cannot read the magic value!')
+            return None
+        else:
+            return self.read_word(self.tz_addr, False)
+
+    def find_hw_id(self, socinfo_id, version):
+        if self.hw_version is not None:
+            version = self.hw_version
+        for cpuid in cpu_of_id:
+            if socinfo_id == cpuid[0]:
+                for hwid in hw_ids:
+                    if cpuid[1] == hwid[HARDWARE_ID_IDX]:
+                        if hwid[VERSION_COMPARE] is not None and hwid[VERSION_COMPARE] != version:
+                            continue
+
+                        return hwid
+        return None
+
+    def get_hw_id(self):
+        heap_toc_offset = self.field_offset('struct smem_shared', 'heap_toc')
+        if heap_toc_offset is None:
+            print_out_str(
+                '!!!! Could not get a necessary offset for auto detection!')
+            print_out_str(
+                '!!!! Please check the gdb path which is used for offsets!')
+            print_out_str('!!!! Also check that the vmlinux is not stripped')
+            print_out_str('!!!! Exiting...')
+            sys.exit(1)
+
+        smem_heap_entry_size = self.sizeof('struct smem_heap_entry')
+        offset_offset = self.field_offset('struct smem_heap_entry', 'offset')
+        socinfo_format = -1
+        socinfo_id = -1
+        socinfo_version = 0
+        socinfo_build_id = 'DUMMY'
+        hwid = None
+
+        if (self.hw_id is None):
+            for smem_offset in smem_offsets:
+                socinfo_start_addr = self.ebi_files[0][
+                    1] + smem_offset + heap_toc_offset + smem_heap_entry_size * SMEM_HW_SW_BUILD_ID + offset_offset
+                soc_start = self.read_word(socinfo_start_addr, False)
+                if soc_start is None:
+                    continue
+
+                socinfo_start = self.ebi_files[0][1] + smem_offset + soc_start
+
+                socinfo_format = self.read_word(socinfo_start, False)
+                socinfo_id = self.read_word(socinfo_start + 4, False)
+                socinfo_version = self.read_word(socinfo_start + 8, False)
+                socinfo_build_id = self.read_cstring(
+                    socinfo_start + 12, BUILD_ID_LENGTH, False)
+
+                if socinfo_id is not None and socinfo_version is not None:
+                    hwid = self.find_hw_id(socinfo_id, socinfo_version >> 16)
+                if (hwid is not None):
+                    break
+            if (hwid is None):
+                print_out_str('!!!! Could not find hardware')
+                print_out_str("!!!! The SMEM didn't match anything")
+                print_out_str(
+                    '!!!! You can use --force-hardware to use a specific set of values')
+                sys.exit(1)
+
+        else:
+            hwid = None
+            for a in hw_ids:
+                if self.hw_id == a[HARDWARE_ID_IDX] and self.hw_version == a[VERSION_COMPARE]:
+                    print_out_str(
+                        '!!! Hardware id found! The socinfo values given are bogus')
+                    print_out_str('!!! Proceed with caution!')
+                    hwid = a
+                    break
+            if hwid is None:
+                print_out_str(
+                    '!!! A bogus hardware id was specified: {0}'.format(self.hw_id))
+                print_out_str(
+                    '!!! Try passing one of these to --force-hardware.')
+                print_out_str(
+                    '!!! If a version is specified, pass the version with --force-version')
+                for a in hw_ids:
+                    if a[VERSION_COMPARE] is not None:
+                        v = 'v{0}'.format(a[VERSION_COMPARE])
+                    else:
+                        v = ''
+                    print_out_str(
+                        '!!!    {0}{1}'.format(a[HARDWARE_ID_IDX], v))
+                sys.exit(1)
+
+        print_out_str('\nHardware match: {0}'.format(hwid[HARDWARE_ID_IDX]))
+        print_out_str('Socinfo id = {0}, version {1:x}.{2:x}'.format(
+            socinfo_id, socinfo_version >> 16, socinfo_version & 0xFFFF))
+        print_out_str('Socinfo build = {0}'.format(socinfo_build_id))
+        print_out_str(
+            'Now setting phys_offset to {0:x}'.format(hwid[PHYS_OFFSET_IDX]))
+        print_out_str(
+            'TZ address: {0:x}'.format(hwid[WATCHDOG_BARK_OFFSET_IDX]))
+        self.phys_offset = hwid[PHYS_OFFSET_IDX]
+        self.tz_addr = hwid[WATCHDOG_BARK_OFFSET_IDX]
+        self.ebi_start = hwid[MEMORY_START_IDX]
+        self.tz_start = hwid[IMEM_START_IDX]
+        self.hw_id = hwid[HARDWARE_ID_IDX]
+        self.cpu_type = hwid[CPU_TYPE]
+        self.imem_fname = hwid[IMEM_FILENAME]
+        return True
+
+    def virt_to_phys(self, virt):
+        return self.mmu.virt_to_phys(virt)
+
+    def setup_symbol_tables(self):
+        stream = os.popen(self.nm_path + ' -n ' + self.vmlinux)
+        symbols = stream.readlines()
+        for line in symbols:
+            s = line.split(' ')
+            if len(s) == 3:
+                self.lookup_table.append((int(s[0], 16), s[2].rstrip()))
+        stream.close()
+
+    def addr_lookup(self, symbol):
+        try:
+            return self.gdbmi.address_of(symbol)
+        except gdbmi.GdbMIException:
+            pass
+
+    def symbol_lookup(self, addr):
+        try:
+            return self.gdbmi.symbol_at(addr).symbol
+        except gdbmi.GdbMIException:
+            pass
+
+    def sizeof(self, the_type):
+        try:
+            return self.gdbmi.sizeof(the_type)
+        except gdbmi.GdbMIException:
+            pass
+
+    def array_index(self, addr, the_type, index):
+        """Index into the array of type `the_type' located at `addr'.
+
+        I.e.:
+
+            Given:
+
+                int my_arr[3];
+                my_arr[2] = 42;
+
+
+            The following:
+
+                my_arr_addr = dump.addr_lookup("my_arr")
+                dump.read_word(dump.array_index(my_arr_addr, "int", 2))
+
+        will return 42.
+
+        """
+        offset = self.gdbmi.sizeof(the_type) * index
+        return addr + offset
+
+    def field_offset(self, the_type, field):
+        try:
+            return self.gdbmi.field_offset(the_type, field)
+        except gdbmi.GdbMIException:
+            pass
+
+    def unwind_lookup(self, addr, symbol_size=0):
+        if (addr is None):
+            return ('(Invalid address)', 0x0)
+
+        # modules are not supported so just print out an address
+        # instead of a confusing symbol
+        if (addr < self.page_offset):
+            return ('(No symbol for address {0:x})'.format(addr), 0x0)
+
+        low = 0
+        high = len(self.lookup_table)
+        # Python now complains about division producing floats
+        mid = (low + high) >> 1
+        premid = 0
+
+        while(not(addr >= self.lookup_table[mid][0] and addr < self.lookup_table[mid + 1][0])):
+
+            if(addr < self.lookup_table[mid][0]):
+                high = mid - 1
+
+            if(addr > self.lookup_table[mid][0]):
+                low = mid + 1
+
+            mid = (high + low) >> 1
+
+            if(mid == premid):
+                return None
+            if (mid + 1) >= len(self.lookup_table) or mid < 0:
+                return None
+
+            premid = mid
+
+        if symbol_size == 0:
+            return (self.lookup_table[mid][1], addr - self.lookup_table[mid][0])
+        else:
+            return (self.lookup_table[mid][1], self.lookup_table[mid + 1][0] - self.lookup_table[mid][0])
+
+    def read_physical(self, addr, length, trace=False):
+        ebi = (-1, -1, -1)
+        for a in self.ebi_files:
+            fd, start, end, path = a
+            if addr >= start and addr <= end:
+                ebi = a
+                break
+        if ebi[0] is -1:
+            return None
+        if trace:
+            print_out_str('reading from {0}'.format(ebi[0]))
+            print_out_str('start = {0:x}'.format(ebi[1]))
+            print_out_str('end = {0:x}'.format(ebi[2]))
+            print_out_str('length = {0:x}'.format(length))
+        offset = addr - ebi[1]
+        if trace:
+            print_out_str('offset = {0:x}'.format(offset))
+        ebi[0].seek(offset)
+        a = ebi[0].read(length)
+        if trace:
+            print_out_str('result = {0}'.format(a))
+            print_out_str('lenght = {0}'.format(len(a)))
+        return a
+
+    def read_dword(self, address, virtual=True, trace=False, cpu=None):
+        if trace:
+            print_out_str('reading {0:x}'.format(address))
+        s = self.read_string(address, '<Q', virtual, trace, cpu)
+        if s is None:
+            return None
+        else:
+            return s[0]
+
+    # returns the 4 bytes read from the specified virtual address
+    # return None on error
+    def read_word(self, address, virtual=True, trace=False, cpu=None):
+        if trace:
+            print_out_str('reading {0:x}'.format(address))
+        s = self.read_string(address, '<I', virtual, trace, cpu)
+        if s is None:
+            return None
+        else:
+            return s[0]
+
+    def read_halfword(self, address, virtual=True, trace=False, cpu=None):
+        if trace:
+            print_out_str('reading {0:x}'.format(address))
+        s = self.read_string(address, '<H', virtual, trace, cpu)
+        if s is None:
+            return None
+        else:
+            return s[0]
+
+    def read_byte(self, address, virtual=True, trace=False, cpu=None):
+        if trace:
+            print_out_str('reading {0:x}'.format(address))
+        s = self.read_string(address, '<B', virtual, trace, cpu)
+        if s is None:
+            return None
+        else:
+            return s[0]
+
+    def read_cstring(self, address, max_length, virtual=True, cpu=None):
+        addr = address
+        if virtual:
+            if cpu is not None:
+                address += pcpu_offset + self.per_cpu_offset(cpu)
+            addr = self.virt_to_phys(address)
+        s = self.read_physical(addr, max_length)
+        if s is not None:
+            a = s.decode('ascii', 'ignore')
+            return a.split('\0')[0]
+        else:
+            return s
+
+    # returns a tuple of the result from reading from the specified fromat string
+    # return None on failure
+    def read_string(self, address, format_string, virtual=True, trace=False, cpu=None):
+        addr = address
+        per_cpu_string = ''
+        if virtual:
+            if cpu is not None:
+                pcpu_offset = self.per_cpu_offset(cpu)
+                address += pcpu_offset
+                per_cpu_string = ' with per-cpu offset of ' + hex(pcpu_offset)
+            addr = self.virt_to_phys(address)
+        if trace:
+            print_out_str('reading from phys {0:x}{1}'.format(addr,
+                                                              per_cpu_string))
+        s = self.read_physical(addr, struct.calcsize(format_string), trace)
+        if (s is None) or (s == ''):
+            if trace:
+                print_out_str(
+                    'address {0:x} failed hard core (v {1} t{2})'.format(addr, virtual, trace))
+            return None
+        return struct.unpack(format_string, s)
+
+    def per_cpu_offset(self, cpu):
+        per_cpu_offset_addr = self.addr_lookup('__per_cpu_offset')
+        if per_cpu_offset_addr is None:
+            return 0
+        per_cpu_offset_addr_indexed = self.array_index(
+            per_cpu_offset_addr, 'unsigned long', cpu)
+        return self.read_word(per_cpu_offset_addr_indexed)
+
+    def get_num_cpus(self):
+        cpu_present_bits_addr = self.addr_lookup('cpu_present_bits')
+        cpu_present_bits = self.read_word(cpu_present_bits_addr)
+        return bin(cpu_present_bits).count('1')
+
+    def iter_cpus(self):
+        return xrange(self.get_num_cpus())
diff --git a/linux-ramdump-parser-v2/ramparse.py b/linux-ramdump-parser-v2/ramparse.py
new file mode 100755
index 0000000000000000000000000000000000000000..4128c2116f411543ea7aa4691c7d965842e880f5
--- /dev/null
+++ b/linux-ramdump-parser-v2/ramparse.py
@@ -0,0 +1,218 @@
+#!/usr/bin/python
+
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import sys
+import os
+from optparse import OptionParser
+
+import parser_util
+from ramdump import RamDump
+from print_out import print_out_str, set_outfile, print_out_section
+
+# Please update version when something is changed!'
+VERSION = '2.0'
+
+
+def parse_ram_file(option, opt_str, value, parser):
+    a = getattr(parser.values, option.dest)
+    if a is None:
+        a = []
+    temp = []
+    for arg in parser.rargs:
+        if arg[:2] == '--':
+            break
+        if arg[:1] == '-' and len(arg) > 1:
+            break
+        temp.append(arg)
+
+    if len(temp) is not 3:
+        raise OptionValueError(
+            "Ram files must be specified in 'name, start, end' format")
+
+    a.append((temp[0], int(temp[1], 16), int(temp[2], 16)))
+    setattr(parser.values, option.dest, a)
+
+if __name__ == '__main__':
+    usage = 'usage: %prog [options to print]. Run with --help for more details'
+    parser = OptionParser(usage)
+    parser.add_option('', '--print-watchdog-time', action='store_true',
+                      dest='watchdog_time', help='Print watchdog timing information', default=False)
+    parser.add_option('-e', '--ram-file', dest='ram_addr',
+                      help='List of ram files (name, start, end)', action='callback', callback=parse_ram_file)
+    parser.add_option('-v', '--vmlinux', dest='vmlinux', help='vmlinux path')
+    parser.add_option('-n', '--nm-path', dest='nm', help='nm path')
+    parser.add_option('-g', '--gdb-path', dest='gdb', help='gdb path')
+    parser.add_option('-a', '--auto-dump', dest='autodump',
+                      help='Auto find ram dumps from the path')
+    parser.add_option('-o', '--outdir', dest='outdir', help='Output directory')
+    parser.add_option('-s', '--t32launcher', action='store_true',
+                      dest='t32launcher', help='Create T32 simulator launcher', default=False)
+    parser.add_option('-x', '--everything', action='store_true',
+                      dest='everything', help='Output everything (may be slow')
+    parser.add_option('-f', '--output-file', dest='outfile',
+                      help='Name of file to save output')
+    parser.add_option('', '--stdout', action='store_true',
+                      dest='stdout', help='Dump to stdout instead of the file')
+    parser.add_option('', '--phys-offset', type='int',
+                      dest='phys_offset', help='use custom phys offset')
+    parser.add_option('', '--force-hardware', type='int',
+                      dest='force_hardware', help='Force the hardware detection')
+    parser.add_option(
+        '', '--force-version', type='int', dest='force_hardware_version',
+        help='Force the hardware detection to a specific hardware version')
+    parser.add_option('', '--parse-qdss', action='store_true',
+                      dest='qdss', help='Parse QDSS (deprecated)')
+
+    for p in parser_util.get_parsers():
+        parser.add_option(p.shortopt or '',
+                          p.longopt,
+                          dest=p.cls.__name__,
+                          help=p.desc,
+                          action='store_true')
+
+    (options, args) = parser.parse_args()
+
+    if options.outdir:
+        if not os.path.exists(options.outdir):
+            print ('!!! Out directory does not exist. Create it first.')
+            sys.exit(1)
+    else:
+        options.outdir = '.'
+
+    if options.outfile is None:
+        # dmesg_TZ is a very non-descriptive name and should be changed
+        # sometime in the future
+        options.outfile = 'dmesg_TZ.txt'
+
+    if not options.stdout:
+        set_outfile(options.outdir + '/' + options.outfile)
+
+    print_out_str('Linux Ram Dump Parser Version %s' % VERSION)
+    if options.vmlinux is None:
+        print_out_str("No vmlinux given. I can't proceed!")
+        parser.print_usage()
+        sys.exit(1)
+
+    args = ''
+    for arg in sys.argv:
+        args = args + arg + ' '
+
+    print_out_str('Arguments: {0}'.format(args))
+
+    system_type = parser_util.get_system_type()
+
+    if not os.path.exists(options.vmlinux):
+        print_out_str(
+            '{0} does not exist. Cannot proceed without vmlinux. Exiting...'.format(options.vmlinux))
+        sys.exit(1)
+    elif not os.path.isfile(options.vmlinux):
+        print_out_str(
+            '{0} is not a file. Did you pass the ram file directory instead of the vmlinux?'.format(options.vmlinux))
+        sys.exit(1)
+    else:
+        print_out_str('using vmlinx file {0}'.format(options.vmlinux))
+
+    if options.ram_addr is None and options.autodump is None:
+        print_out_str('Need one of --auto-dump or at least one --ram-file')
+        sys.exit(1)
+
+    if options.ram_addr is not None:
+        for a in options.ram_addr:
+            if os.path.exists(a[0]):
+                print_out_str(
+                    'Loading Ram file {0} from {1:x}--{2:x}'.format(a[0], a[1], a[2]))
+            else:
+                print_out_str(
+                    'Ram file {0} does not exist. Exiting...'.format(a[0]))
+                sys.exit(1)
+
+    if options.autodump is not None:
+        if os.path.exists(options.autodump):
+            print_out_str(
+                'Looking for Ram dumps in {0}'.format(options.autodump))
+        else:
+            print_out_str(
+                'Path {0} does not exist for Ram dumps. Exiting...'.format(options.autodump))
+            sys.exit(1)
+
+    gdb_path = None
+    nm_path = None
+
+    try:
+        import local_settings
+        gdb_path = local_settings.gdb_path
+        nm_path = local_settings.nm_path
+    except ImportError:
+        cross_compile = os.environ.get('CROSS_COMPILE')
+        if cross_compile is not None:
+            gdb_path = cross_compile+"gdb"
+            nm_path = cross_compile+"nm"
+
+    if gdb_path is None or nm_path is None:
+        print_out_str("!!! Incorrect path for toolchain specified.")
+        print_out_str("!!! Please see the README for instructions on setting up local_settings.pyi or CROSS_COMPILE")
+        sys.exit(1)
+
+    print_out_str("Using gdb path {0}".format(gdb_path))
+    print_out_str("Using nm path {0}".format(nm_path))
+
+    if not os.path.exists(gdb_path):
+        print_out_str("!!! gdb_path {0} does not exist! Check your settings!".format(gdb_path))
+        sys.exit(1)
+
+    if not os.access(gdb_path, os.X_OK):
+        print_out_str("!!! No execute permissions on gdb path {0}".format(gdb_path))
+        print_out_str("!!! Please check the path settings")
+        print_out_str("!!! If this tool is being run from a shared location, contact the maintainer")
+        sys.exit(1)
+
+    if not os.path.exists(nm_path):
+        print_out_str("!!! nm_path {0} does not exist! Check your settings!".format(gdb_path))
+        sys.exit(1)
+
+    if not os.access(nm_path, os.X_OK):
+        print_out_str("!!! No execute permissions on nm path {0}".format(gdb_path))
+        print_out_str("!!! Please check the path settings")
+        print_out_str("!!! If this tool is being run from a shared location, contact the maintainer")
+        sys.exit(1)
+
+    dump = RamDump(options.vmlinux, nm_path, gdb_path, options.ram_addr,
+                   options.autodump, options.phys_offset, options.outdir,
+                   options.force_hardware, options.force_hardware_version)
+
+    if not dump.print_command_line():
+        print_out_str('!!! Error printing saved command line.')
+        print_out_str('!!! The vmlinux is probably wrong for the ramdumps')
+        print_out_str('!!! Exiting now...')
+        sys.exit(1)
+
+    if options.qdss:
+        print_out_str('!!! --parse-qdss is now deprecated')
+        print_out_str(
+            '!!! Please just use --parse-debug-image to get QDSS information')
+
+    if options.watchdog_time:
+        print_out_str('\n--------- watchdog time -------')
+        get_wdog_timing(dump)
+        print_out_str('---------- end watchdog time-----')
+
+    for p in parser_util.get_parsers():
+        # we called parser.add_option with dest=p.cls.__name__ above,
+        # so if the user passed that option then `options' will have a
+        # p.cls.__name__ attribute.
+        if getattr(options, p.cls.__name__) or (options.everything and not p.optional):
+            with print_out_section(p.cls.__name__):
+                p.cls(dump).parse()
+
+    if options.t32launcher or options.everything:
+        dump.create_t32_launcher()
diff --git a/linux-ramdump-parser-v2/rb_tree.py b/linux-ramdump-parser-v2/rb_tree.py
new file mode 100644
index 0000000000000000000000000000000000000000..8a6732616b8faf37dbfb46c751457631c6ccd144
--- /dev/null
+++ b/linux-ramdump-parser-v2/rb_tree.py
@@ -0,0 +1,43 @@
+# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+"""
+struct rb_node
+{
+	unsigned long  rb_parent_color;
+#define	RB_RED		0
+#define	RB_BLACK	1
+	struct rb_node *rb_right;
+	struct rb_node *rb_left;
+} __attribute__((aligned(sizeof(long))));
+"""
+
+
+class RbTreeWalker(object):
+
+    def __init__(self, ram_dump):
+        self.ram_dump = ram_dump
+        self.right_offset = self.ram_dump.field_offset(
+            'struct rb_node', 'rb_right')
+        self.left_offset = self.ram_dump.field_offset(
+            'struct rb_node', 'rb_left')
+
+    def walk(self, node, func):
+        if node != 0:
+            left_node_addr = node + self.left_offset
+            left_node = self.ram_dump.read_word(left_node_addr)
+            self.walk(left_node, func)
+
+            func(node)
+
+            right_node_addr = node + self.right_offset
+            right_node = self.ram_dump.read_word(right_node_addr)
+            self.walk(right_node, func)
diff --git a/linux-ramdump-parser-v2/register.py b/linux-ramdump-parser-v2/register.py
new file mode 100644
index 0000000000000000000000000000000000000000..5acd9f9ad95a91c53ae8b8a1f6952632295c5c92
--- /dev/null
+++ b/linux-ramdump-parser-v2/register.py
@@ -0,0 +1,102 @@
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# 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.
+
+import bitops
+
+
+class Register(object):
+
+    """Represents a register (or any general field partitioning of
+    bits). Provides easy read and write access to the fields in the
+    register by taking care of all bit-shifting automatically. Fields
+    can be defined at __init__ time using kwargs or can be added
+    dynamically with `add_field'. Fields are accessible as instance
+    attributes.
+
+    For example:
+
+    >>> abc = Register(0x42, stuff=(2, 0))
+    >>> abc
+    value: 0x42 {stuff[2:0]=>0x2}
+    >>> hex(abc.value)
+    '0x42'
+    >>> hex(abc.stuff)
+    '0x2'
+    >>> abc.stuff = 1
+    >>> hex(abc.value)
+    '0x41'
+    >>> abc.add_field("other", (8, 4))
+    >>> hex(abc.other)
+    '0x4'
+    >>> abc.other = 0x3
+    >>> hex(abc.value)
+    '0x31'
+
+    You can also overlay fields on top of each other without problems:
+
+    >>> abc.add_field("another_other", (8, 0))
+    abc.another_other = 0x5
+    >>> hex(abc.value)
+    '0x5'
+
+    """
+
+    def __init__(self, value=0, **kwargs):
+        """Register constructor.
+
+        kwargs should represent the fields in this object. Their
+        values should be 2-tuples of the form (msb, lsb).
+
+        """
+
+        # All the object.__setattr__ stuff is to prevent us from going
+        # into our __setattr__ method here (which would try to access
+        # these again and would then recurse inifitely)
+        object.__setattr__(self, 'value', value)
+        object.__setattr__(self, '_regs', {})
+        for (k, v) in kwargs.iteritems():
+            self.add_field(k, v)
+
+    def add_field(self, field, bitrange):
+        """Add field to Register.
+
+        bitrange should be the same format as the kwargs in __init__
+        (i.e. (msb, lsb)).
+
+        """
+        self._regs[field] = bitrange
+
+    def __dir__(self):
+        return self.__dict__.keys() + self._regs.keys()
+
+    def __getattr__(self, name):
+        if name not in self._regs:
+            raise AttributeError
+        msb, lsb = self._regs[name]
+        return bitops.bvalsel(msb, lsb, self.value)
+
+    def __setattr__(self, name, newvalue):
+        if name not in self._regs:
+            raise AttributeError
+        msb, lsb = self._regs[name]
+        val = self.value & (~bitops.bm(msb, lsb))
+        val |= newvalue << lsb
+        # can't access self.value directly since that would cause
+        # infinite recursion to __setattr__
+        object.__setattr__(self, 'value', val)
+
+    def __repr__(self):
+        ret = []
+        for r in sorted(self._regs, key=self._regs.get, reverse=True):
+            msb, lsb = self._regs[r]
+            val = bitops.bvalsel(msb, lsb, self.value)
+            ret.append('%s[%d:%d]=>0x%0x' % (r, msb, lsb, val))
+        return 'value: 0x%x {%s}' % (self.value, ', '.join(ret))