diff --git a/linux-ramdump-parser-v2/parsers/slabinfo.py b/linux-ramdump-parser-v2/parsers/slabinfo.py
old mode 100755
new mode 100644
index 0f9a95a47ef65284798cb3c6568a742bbf580738..460c08ea5cc108e9dd060dc098c8a1d028180707
--- a/linux-ramdump-parser-v2/parsers/slabinfo.py
+++ b/linux-ramdump-parser-v2/parsers/slabinfo.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+# Copyright (c) 2012-2016, 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
@@ -9,11 +9,12 @@
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 
-import re
+import sys
 
 from mm import page_address, pfn_to_page
 from print_out import print_out_str
 from parser_util import register_parser, RamParser
+import operator
 
 SLAB_RED_ZONE = 0x400
 SLAB_POISON = 0x800
@@ -25,52 +26,80 @@ SLUB_RED_ACTIVE = 0xcc
 POISON_INUSE = 0x5a
 POISON_FREE = 0x6b
 POISON_END = 0xa5
+g_printfreeobjStack = False
+
 
 class kmem_cache(object):
     def __init__(self, ramdump, addr):
         self.valid = False
-
         offset = ramdump.field_offset(
             'struct kmem_cache', 'flags')
         self.flags = ramdump.read_word(addr + offset)
         if self.flags is None:
             return
-
         offset = ramdump.field_offset(
             'struct kmem_cache', 'size')
         self.size = ramdump.read_int(addr + offset)
         if self.size is None:
             return
-
         offset = ramdump.field_offset(
             'struct kmem_cache', 'object_size')
         self.object_size = ramdump.read_int(addr + offset)
         if self.object_size is None:
             return
-
         offset = ramdump.field_offset(
             'struct kmem_cache', 'offset')
         self.offset = ramdump.read_int(addr + offset)
         if self.offset is None:
             return
-
-        offset = ramdump.field_offset(
-            'struct kmem_cache', 'max')
-        self.max = ramdump.read_word(addr + offset)
-        if self.max is None:
-            return
-
         offset = ramdump.field_offset(
             'struct kmem_cache', 'inuse')
         self.inuse = ramdump.read_int(addr + offset)
         if self.inuse is None:
             return
-
         self.addr = addr
         self.valid = True
 
+
+class struct_member_offset(object):
+    def __init__(self, ramdump):
+        self.kmemcache_list = ramdump.field_offset(
+            'struct kmem_cache', 'list')
+        self.kmemcache_name = ramdump.field_offset(
+            'struct kmem_cache', 'name')
+        self.kmemcache_node = ramdump.field_offset(
+            'struct kmem_cache', 'node')
+        self.kmemcache_cpu_page = ramdump.field_offset(
+            'struct kmem_cache_cpu', 'page')
+        self.kmemcpucache_cpu_slab = ramdump.field_offset(
+            'struct kmem_cache', 'cpu_slab')
+        self.kmemcachenode_partial = ramdump.field_offset(
+            'struct kmem_cache_node', 'partial')
+        self.kmemcachenode_full = ramdump.field_offset(
+                            'struct kmem_cache_node', 'full')
+        self.page_lru = ramdump.field_offset(
+                            'struct page', 'lru')
+        self.page_flags = ramdump.field_offset(
+                            'struct page', 'flags')
+        self.page_mapcount = ramdump.field_offset(
+                            'struct page', '_mapcount')
+        self.track_addrs = ramdump.field_offset(
+                            'struct track', 'addrs')
+        self.page_freelist = ramdump.field_offset(
+                            'struct page', 'freelist')
+        self.sizeof_struct_track = ramdump.sizeof(
+                                            'struct track')
+        self.sizeof_void_pointer = ramdump.sizeof(
+                                             "void *")
+        self.sizeof_unsignedlong = ramdump.sizeof(
+                                             "unsigned long")
+
+
 @register_parser('--slabinfo', 'print information about slabs', optional=True)
 class Slabinfo(RamParser):
+    g_allstacks = {}  # hold callstack stack
+    g_index = 0
+    g_offsetof = None
 
     def get_free_pointer(self, ramdump, s, obj):
         # just like validate_slab_slab!
@@ -80,72 +109,278 @@ class Slabinfo(RamParser):
         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)
+        freelist = self.ramdump.read_word(page + g_offsetof.page_freelist)
         p = freelist
         addr = page_address(self.ramdump, page)
         seen = []
         if addr is None:
             return
         while p != 0 and p is not None and p not in seen:
-            idx = self.slab_index(self.ramdump, p, addr, slab)
-            if idx >= len(bitarray) or idx < 0:
+            index = self.slab_index(self.ramdump, p, addr, slab)
+            if index >= len(bitarray) or index < 0:
                 return
-            bitarray[idx] = 1
+            bitarray[index] = 1
             seen.append(p)
             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_int(slab + slab_offset_offset)
-        slab_inuse = self.ramdump.read_int(slab + slab_inuse_offset)
-        if slab_offset != 0:
-            p = obj + slab_offset + self.ramdump.sizeof("void *")
+    def get_track(self, ramdump,  slab, obj, track_type):
+        track_size = g_offsetof.sizeof_struct_track
+        if slab.offset != 0:
+            p = obj + slab.offset + g_offsetof.sizeof_void_pointer
         else:
-            p = obj + slab_inuse
+            p = obj + slab.inuse
         return p + track_type * track_size
 
+    def extract_callstack(self, ramdump, a, stack, out_file):
+        for a in stack:
+            look = ramdump.unwind_lookup(a)
+            if look is None:
+                out_file.write("look is None")
+                continue
+            symname, offset = look
+            out_file.write(
+                '      [<{0:x}>] {1}+0x{2:x}\n'.format(a, symname, offset))
+        return
+
     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')
+        stack = []
+        stackstr = ""
+        p = self.get_track(ramdump, slab, obj, track_type)
+        track_addrs_offset = g_offsetof.track_addrs
         start = p + track_addrs_offset
-        pointer_size = self.ramdump.sizeof("unsigned long")
-        if track_type == 0:
-            out_file.write('   ALLOC STACK\n')
-        else:
-            out_file.write('   FREE STACK\n')
+        pointer_size = g_offsetof.sizeof_unsignedlong
         for i in range(0, 16):
             a = self.ramdump.read_word(start + pointer_size * i)
             if a == 0:
-                break
-            look = self.ramdump.unwind_lookup(a)
-            if look is None:
+                continue
+            stack += [a]
+            stackstr += str(a)
+        stackstr_len = len(stackstr)
+        if stackstr_len == 0:
+            return
+        try:
+            self.g_allstacks[stackstr][0] += 1
+            if self.g_allstacks[stackstr][0] > 1:
                 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
+            self.extract_callstack(self.ramdump, a, stack, out_file)
+        except KeyError:
+            if g_printfreeobjStack is False:
+                if track_type != 0:
+                    # if free object and g_printfreeobjStack is False,
+                    # ignore it for printing its call stack
+                    return
+            if track_type == 1:
+                out_file.write(
+                        "FREE Call stack index:{0}".format(
+                                                            self.g_index))
+            else:
+                out_file.write(
+                        "ALLOCATED Call stack index:{0}".format(
+                                                                self.g_index))
+            self.extract_callstack(self.ramdump, a, stack, out_file)
+            self.g_allstacks[stackstr] = [1, self.g_index]
+            self.g_index += 1
+            out_file.write('\n')
+
+    def print_slab(
+                self, ramdump, slab, page,
+                out_file, map_fn, out_slabs_addrs):
+
+        page_addr = page_address(ramdump, page)
+        p = page_addr
+        if page is None:
+            return
+        n_objects = self.ramdump.read_word(page + g_offsetof.page_mapcount)
+        n_objects = (n_objects >> 16) & 0x00007FFF
+        if n_objects is None:
+            return
+        bitarray = [0] * n_objects
+        addr = page_address(self.ramdump, page)
+        self.get_map(self.ramdump, slab, page, bitarray)
+        while p < page_addr + (n_objects * slab.size):
+            bitidx = self.slab_index(self.ramdump, p, addr, slab)
+            if bitidx >= n_objects or bitidx < 0:
+                return
+            map_fn(
+                        ramdump, p, bitarray[bitidx], slab,
+                        page, out_file, out_slabs_addrs)
+            p = p + slab.size
+
+    def printsummary(self, slabs_output_summary):
+        sorted_val = sorted(
+                            self.g_allstacks.items(),
+                            key=operator.itemgetter(1), reverse=True)
+        for key, value in sorted_val:
+            slabs_output_summary.write(
+                " stack index:{0} frequency:{1}\n".format(value[1], value[0]))
+
+    def print_slab_page_info(
+                self, ramdump, slab_obj, slab_node, start,
+                out_file, map_fn, out_slabs_addrs):
+        page = self.ramdump.read_word(start)
+        if page == 0:
+            return
+        seen = []
+        max_pfn_addr = self.ramdump.address_of('max_pfn')
+        max_pfn = self.ramdump.read_word(max_pfn_addr)
+        max_page = pfn_to_page(ramdump, max_pfn)
+        while page != start:
+            if page is None:
+                return
+            if page in seen:
+                return
+            if page > max_page:
+                return
+            seen.append(page)
+            page = page - g_offsetof.page_lru
+            self.print_slab(
+                self.ramdump, slab_obj, page, out_file, map_fn,
+                out_slabs_addrs)
+            page = self.ramdump.read_word(page + g_offsetof.page_lru)
+
+    def print_per_cpu_slab_info(
+            self, ramdump, slab, slab_node, start, out_file, map_fn):
+        page = self.ramdump.read_word(start)
+        if page == 0:
+            return
+        if page is None:
+            return
+        page_addr = page_address(self.ramdump, page)
+        self.print_slab(
+            self.ramdump, page_addr, slab, page, out_file, map_fn)
+
+    def print_all_objects(
+            self, ramdump, p, free, slab, page, out_file, out_slabs_addrs):
+
+        if free:
+            out_slabs_addrs.write(
+                '\n   Object {0:x}-{1:x} FREE'.format(
+                                    p, p + slab.size))
+        else:
+            out_slabs_addrs.write(
+                '\n   Object {0:x}-{1:x} ALLOCATED'.format(
+                                p, p + slab.size))
+        if self.ramdump.is_config_defined('CONFIG_SLUB_DEBUG_ON'):
+            if g_printfreeobjStack is True:
+                self.print_track(ramdump, slab, p, 0, out_file)
+                self.print_track(ramdump, slab, p, 1, out_file)
+            else:
+                self.print_track(ramdump, slab, p, free, out_file)
+
+    def print_check_poison(self, p, free, slab, page, out_file):
+        if free:
+            self.check_object(slab, page, p, SLUB_RED_INACTIVE, out_file)
         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_int(page + map_count_offset)
-            if count is None:
-                return None
-            n_objects = (count >> 16) & 0xFFFF
-            return n_objects
+            self.check_object(slab, page, p, SLUB_RED_ACTIVE, out_file)
+
+    def initializeOffset(self):
+        global g_offsetof
+        g_offsetof = struct_member_offset(self.ramdump)
+
+    # 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 validate_slab_cache(self, slab_out, input_slabname,  map_fn):
+        slab_name_found = False
+        original_slab = self.ramdump.address_of('slab_caches')
+        cpu_present_bits_addr = self.ramdump.address_of('cpu_present_bits')
+        cpu_present_bits = self.ramdump.read_word(cpu_present_bits_addr)
+        cpus = bin(cpu_present_bits).count('1')
+        offsetof = struct_member_offset(self.ramdump)
+        self.initializeOffset()
+        slab_list_offset = g_offsetof.kmemcache_list
+        slab_name_offset = g_offsetof.kmemcache_name
+        slab_node_offset = g_offsetof.kmemcache_node
+        cpu_slab_offset = g_offsetof.kmemcpucache_cpu_slab
+        slab_partial_offset = g_offsetof.kmemcachenode_partial
+        slab_full_offset = g_offsetof.kmemcachenode_full
+        slab = self.ramdump.read_word(original_slab)
+        slabs_output_summary = self.ramdump.open_file('slabs_output.txt')
+        out_slabs_addrs = self.ramdump.open_file('out_slabs_addrs.txt')
+        while slab != original_slab:
+            slab = slab - slab_list_offset
+            slab_obj = kmem_cache(self.ramdump, slab)
+            if not slab_obj.valid:
+                slab_out.write(
+                        'Invalid slab object {0:x}'.format(slab))
+                slab = self.ramdump.read_word(slab + slab_list_offset)
+                continue
+            slab_name_addr = self.ramdump.read_word(
+                                        slab + slab_name_offset)
+            slab_name = self.ramdump.read_cstring(
+                                        slab_name_addr, 48)
+            if input_slabname is not None:
+                if input_slabname != slab_name:
+                    slab = self.ramdump.read_word(slab + slab_list_offset)
+                    continue
+                else:
+                    slab_name_found = True
+            # 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)
+            print_out_str(
+                '\nExtracting slab details of : {0}'.format(
+                                                                    slab_name))
+            cpu_slab_addr = self.ramdump.read_word(
+                                        slab + cpu_slab_offset)
+            nr_total_objects = self.ramdump.read_structure_field(
+                        slab_node_addr,
+                        'struct kmem_cache_node', 'total_objects')
+            slab_out.write(
+                '\n {0:x} slab {1} {2:x}  total objects: {3}\n'.format(
+                        slab, slab_name, slab_node_addr, nr_total_objects))
+
+            self.print_slab_page_info(
+                self.ramdump, slab_obj, slab_node,
+                slab_node_addr + slab_partial_offset,
+                slab_out, map_fn, out_slabs_addrs)
+
+            if self.ramdump.is_config_defined('CONFIG_SLUB_DEBUG'):
+                self.print_slab_page_info(
+                    self.ramdump, slab_obj, slab_node,
+                    slab_node_addr + slab_full_offset,
+                    slab_out, map_fn, out_slabs_addrs)
+
+            # per cpu slab
+            for i in range(0, cpus):
+                cpu_slabn_addr = self.ramdump.read_word(
+                                                cpu_slab_addr, cpu=i)
+                if cpu_slabn_addr == 0 or None:
+                    break
+                self.print_per_cpu_slab_info(
+                    self.ramdump, slab_obj,
+                    slab_node, cpu_slabn_addr + offsetof.cpu_cache_page_offset,
+                    slab_out, map_fn)
+
+            self.printsummary(slabs_output_summary)
+            self.g_allstacks.clear()
+            if slab_name_found is True:
+                break
+            slab = self.ramdump.read_word(slab + slab_list_offset)
+        out_slabs_addrs.close()
+        slabs_output_summary.close()
+
+    def parse(self):
+        global g_printfreeobjStack
+        slabname = None
+        for arg in sys.argv:
+            if 'slabname=' in arg:
+                k, slabname = arg.split('=')
+            if 'freeobj' in arg:
+                g_printfreeobjStack = True
+        slab_out = self.ramdump.open_file('slabs.txt')
+        self.validate_slab_cache(slab_out, slabname, self.print_all_objects)
+        slab_out.close()
+
+
+@register_parser('--slabpoison', 'check slab poison', optional=True)
+class Slabpoison(Slabinfo):
+    """Note that this will NOT find any slab errors which are printed out by the
+    kernel, because the slab object is removed from the freelist while being
+    processed"""
 
     def print_section(self, text, addr, length, out_file):
         out_file.write('{}\n'.format(text))
@@ -250,138 +485,6 @@ class Slabinfo(RamParser):
             # check_pad_bytes cleans up on its own.
             self.check_pad_bytes(s, page, p, out_file)
 
-
-    def print_slab(self, ramdump, slab_start, slab, page, out_file, map_fn):
-        p = slab_start
-        if page is None:
-            return
-        n_objects = self.get_nobjects(self.ramdump, page)
-        if n_objects 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
-            map_fn(p, bitarray[bitidx], slab, page, out_file)
-            p = p + slab.size
-
-    def print_slab_page_info(self, ramdump, slab, slab_node, start, out_file, map_fn):
-        page = self.ramdump.read_word(start)
-        seen = []
-        if page == 0:
-            return
-        slab_lru_offset = self.ramdump.field_offset('struct page', 'lru')
-        page_flags_offset = self.ramdump.field_offset('struct page', 'flags')
-        max_pfn_addr = self.ramdump.address_of('max_pfn')
-        max_pfn = self.ramdump.read_word(max_pfn_addr)
-        max_page = pfn_to_page(ramdump, max_pfn)
-        while page != start:
-            if page is None:
-                return
-            if page in seen:
-               return
-            if page > max_page:
-               return
-            seen.append(page)
-            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, map_fn)
-            page = self.ramdump.read_word(page + slab_lru_offset)
-
-    def print_per_cpu_slab_info(self, ramdump, slab, slab_node, start, out_file, map_fn):
-        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, map_fn)
-
-    def print_all_objects(self, p, free, slab, page, out_file):
-        if free:
-            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)
-
-    def print_check_poison(self, p, free, slab, page, out_file):
-        if free:
-            self.check_object(slab, page, p, SLUB_RED_INACTIVE, out_file)
-        else:
-            self.check_object(slab, page, p, SLUB_RED_ACTIVE, 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 validate_slab_cache(self, slab_out, map_fn):
-        original_slab = self.ramdump.address_of('slab_caches')
-        cpu_present_bits_addr = self.ramdump.address_of('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 = self.ramdump.read_word(original_slab)
-        while slab != original_slab:
-            slab = slab - slab_list_offset
-            slab_obj = kmem_cache(self.ramdump, slab)
-            if not slab_obj.valid:
-                continue
-            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_obj, slab_node, slab_node_addr + slab_partial_offset, slab_out, map_fn)
-            if self.ramdump.is_config_defined('CONFIG_SLUB_DEBUG'):
-               slab_full_offset = self.ramdump.field_offset(
-                    'struct kmem_cache_node', 'full')
-               self.print_slab_page_info(
-                    self.ramdump, slab_obj, slab_node, slab_node_addr + slab_full_offset, slab_out, map_fn)
-
-            for i in range(0, cpus):
-                cpu_slabn_addr = self.ramdump.read_word(cpu_slab_addr, cpu=i)
-                self.print_per_cpu_slab_info(
-                    self.ramdump, slab_obj, slab_node, cpu_slabn_addr + cpu_cache_page_offset, slab_out, map_fn)
-
-            slab = self.ramdump.read_word(slab + slab_list_offset)
-
-    def parse(self):
-        slab_out = self.ramdump.open_file('slabs.txt')
-        self.validate_slab_cache(slab_out, self.print_all_objects)
-        print_out_str('---wrote slab information to slabs.txt')
-
-@register_parser('--slabpoison', 'check slab poison', optional=True)
-class Slabpoison(Slabinfo):
-    """Note that this will NOT find any slab errors which are printed out by the
-    kernel, because the slab object is removed from the freelist while being
-    processed"""
-
     # since slabs are relatively "packed", caching has a large
     # performance benefit
     def read_byte_array(self, addr, size):
@@ -406,5 +509,5 @@ class Slabpoison(Slabinfo):
         self.cache = None
         self.cache_addr = None
         slab_out = self.ramdump.open_file('slabpoison.txt')
-        self.validate_slab_cache(slab_out, self.print_check_poison)
+        self.validate_slab_cache(slab_out, None, self.print_check_poison)
         print_out_str('---wrote slab information to slabpoison.txt')