From 32c4833f41656fb359380ee01a4eb8908f06ef2f Mon Sep 17 00:00:00 2001
From: Patrick Daly <pdaly@codeaurora.org>
Date: Mon, 11 Dec 2017 19:37:02 -0800
Subject: [PATCH] lrdp: rbtree: Support error recovery during tree iteration

In some cases it may be possible to detect whether an rbtree is corrupted.
Skip over any corrupted nodes, and their children, while iterating.
Additionally, log a message whenever a bad entry is detected. This behavior
may be enabled by the client by setting the 'logger' and 'debug' properties
for a particular instance of an RbTree.

Modify the --print-ionbuffer parser to use the new RbTree implementation.

Change-Id: I2ed2364b5e7d42ee009a0a49876feb82ab0fa78c
---
 .../parsers/ion_buffer_parse.py               |  46 +++---
 linux-ramdump-parser-v2/rb_tree.py            | 136 +++++++++++++++++-
 2 files changed, 161 insertions(+), 21 deletions(-)

diff --git a/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py b/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py
index 47972f1..851efeb 100644
--- a/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py
+++ b/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py
@@ -1,5 +1,5 @@
 """
-Copyright (c) 2016, The Linux Foundation. All rights reserved.
+Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -28,6 +28,9 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 """
 
 from parser_util import register_parser, RamParser
+from rb_tree import RbTree
+import logging
+import os
 
 RB_PARENT_COLOR_MASK = 0xFFFFFFFFFFFFFFFC
 grand_total = 0
@@ -112,13 +115,12 @@ def parse_heap(self, ramdump, heap_addr,  ion_info):
     ion_dev = ramdump.read_structure_field(
                     ion_heap, 'struct ion_heap',  'dev')
 
-    ion_dev_rb_root = ramdump.read_structure_field(
-                    ion_dev, 'struct ion_device',  'clients')
+    clients_rb_root = ion_dev + ramdump.field_offset('struct ion_device',  'clients')
 
     if ionheap_total_allocated != 0:
         nr_clients = show_ion_dev_client(
                             self, ramdump,
-                            ion_dev_rb_root,
+                            clients_rb_root,
                             ionheap_id, ion_info)
 
         str = "\n \nTotal number of clients: {0:1}"
@@ -142,11 +144,9 @@ def parse_heap(self, ramdump, heap_addr,  ion_info):
 def parse_orphan_buffers(self, ramdump, ion_dev, heap_id, ion_info):
     orphan_buffer_size = 0
     total_buffer_size = 0
-    ion_dev_buffer_rb_root = ramdump.read_structure_field(
-                    ion_dev, 'struct ion_device',  'buffers')
 
-    rb_node = parser(
-                self, 1, ramdump,  ion_dev_buffer_rb_root,  ion_info)
+    rbtree = RbTree(ramdump, ion_dev + ramdump.field_offset('struct ion_device', 'buffers'),
+                    logger = self.logger, debug = True)
 
     ion_buffer_rb_node_offset = ramdump.field_offset(
                                 'struct ion_buffer', 'node')
@@ -156,7 +156,7 @@ def parse_orphan_buffers(self, ramdump, ion_dev, heap_id, ion_info):
                                 'struct ion_buffer', 'ref')
     str = "\n buffer: 0x{0:x}, Buffer size: {1} KB "
     str = str + "comm: {2} PID: {3} kmap count: {4} ref_count : {5}"
-    while rb_node != 0:
+    for rb_node in rbtree:
         ion_buffer = rb_node - ion_buffer_rb_node_offset
         ion_buffer_ref_add = ion_buffer + ion_buffer_ref_offset
         ion_buffer_heap = ramdump.read_structure_field(
@@ -188,19 +188,20 @@ def parse_orphan_buffers(self, ramdump, ion_dev, heap_id, ion_info):
                                             ion_buffer_kmap_count,
                                             ref_counter))
                 orphan_buffer_size = orphan_buffer_size + ion_buffer_size
-        rb_node = parser(self, 2, ramdump,  rb_node, ion_info)
     return orphan_buffer_size,  total_buffer_size
 
 
 def show_ion_dev_client(
                         self,
                         ramdump,
-                        ion_dev_rb_root,
+                        rb_root,
                         ionheap_id, ion_info):
     global ion_heap_buffers
     nr_clients = 0
     client_name = 0
-    rb_node = parser(self, 1, ramdump,  ion_dev_rb_root,  ion_info)
+
+    rbtree = RbTree(ramdump, rb_root, logger = self.logger, debug = True)
+
     ion_client_node_offset = ramdump.field_offset(
                             'struct ion_client',  'node')
     task_comm_offset = ramdump.field_offset(
@@ -208,8 +209,8 @@ def show_ion_dev_client(
     tempstr = "\n\n CLIENT: (struct ion_client *)0x{0:x} ,  "
     str = tempstr + "task : {1} / ion_client : {2} / PID: {3} / Size : {4} KB"
     str1 = tempstr + "ion_client : {1} / PID: {2} / Size : {3} KB"
-    if rb_node != 0:
-        while rb_node != 0:
+    if True:
+        for rb_node in rbtree:
             ion_client = rb_node - ion_client_node_offset
             heap_size = traverse_ion_heap_buffer(
                                                             self,
@@ -244,7 +245,6 @@ def show_ion_dev_client(
                                     client_PID, bytes_to_KB(heap_size)))
                 for heap_buffer in ion_heap_buffers:
                     ion_info.write(heap_buffer)
-            rb_node = parser(self, 2, ramdump,  rb_node,  ion_info)
     return nr_clients
 
 
@@ -256,9 +256,11 @@ def traverse_ion_heap_buffer(self, ramdump, ion_client,  ionheap_id, ion_info):
     ion_buffer_heap_size = 0
     ion_heap_buffers = []
     str = "\n (+) ion_buffer: 0x{0:x} size: {1:0} KB Handle Count: {2:0}"
-    ion_handle_rb_node = parser(
-                        self, 1, ramdump, ion_handle_root_address, ion_info)
-    while ion_handle_rb_node != 0:
+
+    rbtree = RbTree(ramdump, ion_handle_root_address,
+                    logger=self.logger, debug = True)
+
+    for ion_handle_rb_node in rbtree:
         ion_handle = ion_handle_rb_node - self.ion_handle_node_offset
         ion_buffer = ramdump.read_structure_field(
                             ion_handle, 'struct ion_handle', 'buffer')
@@ -278,8 +280,6 @@ def traverse_ion_heap_buffer(self, ramdump, ion_client,  ionheap_id, ion_info):
                             bytes_to_KB(ion_buffer_size),
                             ion_buffer_handlecount)
             ion_heap_buffers.append(temp)
-        ion_handle_rb_node = parser(
-                            self, 2, ramdump, ion_handle_rb_node, ion_info)
     return ion_buffer_heap_size
 
 
@@ -368,4 +368,10 @@ class DumpIonBuffer(RamParser):
                 {1}'.format(self.ramdump.kernel_version[0],
                             self.ramdump.kernel_version[1]))
                 return
+
+            self.logger = logging.getLogger(__name__)
+            path = os.path.join(self.ramdump.outdir, 'print-ionbuffer.stderr')
+            self.logger.addHandler(logging.FileHandler(path, mode='w'))
+            self.logger.setLevel(logging.INFO)
+            self.logger.info("Starting --print-ionbuffer")
             do_dump_ionbuff_info(self, self.ramdump, ion_info)
diff --git a/linux-ramdump-parser-v2/rb_tree.py b/linux-ramdump-parser-v2/rb_tree.py
index 0eacfd0..dbace5e 100644
--- a/linux-ramdump-parser-v2/rb_tree.py
+++ b/linux-ramdump-parser-v2/rb_tree.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+# Copyright (c) 2012-2014, 2018 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,6 +9,9 @@
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 
+from print_out import print_out_str
+import pdb
+
 """
 struct rb_node
 {
@@ -20,6 +23,137 @@ struct rb_node
 } __attribute__((aligned(sizeof(long))));
 """
 
+class RbTree(object):
+
+    def __init__(self, ramdump, root,
+                logger = None, debug = False):
+        self.rd = ramdump
+        self.rb_root = root
+
+        if not logger:
+            self.logger = logging.getLogger(__name__)
+        else:
+            self.logger = logger
+        self.debug = debug
+
+    def __rb_parent(self, node):
+        parent_color = self.rd.read_structure_field(
+                            node, 'struct rb_node', '__rb_parent_color')
+        if  parent_color is None:
+            pdb.set_trace()
+            self.logger.error("struct rb_node@0x{:x}: Memory access failed".format(node))
+            return 0x0
+
+        return parent_color & ~3
+
+    def __rb_left(self, node):
+        child = self.rd.read_structure_field(node, 'struct rb_node', 'rb_left')
+        if child is None:
+            pdb.set_trace()
+            self.logger.error("struct rb_node@0x{:x}: Memory access failed".format(node))
+            return 0x0
+
+        return child
+
+    def __rb_right(self, node):
+        child = self.rd.read_structure_field(node, 'struct rb_node', 'rb_right')
+        if child is None:
+            pdb.set_trace()
+            self.logger.error("struct rb_node@0x{:x}: Memory access failed".format(node))
+            return 0x0
+
+        return child
+
+    def validate(self, parent, child):
+        if not self.debug:
+            return True
+
+        if not parent or not child:
+            return True
+
+        _parent = self.__rb_parent(child)
+        if parent != _parent:
+            self.logger.error(
+                            "Bad rb_tree child->parent pointer:\n"+
+                            "Parent:    0x{:x}\n".format(parent)+
+                            "Child:     0x{:x}\n".format(child))
+            return False
+
+        right = self.__rb_right(parent)
+        left  = self.__rb_left(parent)
+        if (child != left and child != right):
+            self.logger.error(
+                            "Bad rb_tree parent->child pointer:\n"+
+                            "Parent:    0x{:x}\n".format(parent)+
+                            "Child:     0x{:x}\n".format(child))
+            return False
+
+        return True
+
+
+    def rb_parent(self, node):
+        parent = self.__rb_parent(node)
+        if self.validate(parent, node):
+            return parent
+
+    def rb_left(self, node):
+        child = self.__rb_left(node)
+        if self.validate(node, child):
+            return child
+
+    def rb_right(self, node):
+        child = self.__rb_right(node)
+        if self.validate(node, child):
+            return child
+
+    def rb_first(self, node):
+        if not node:
+            return 0x0
+
+        while node:
+            prev = node
+            node = self.rb_left(node)
+
+        return prev
+
+    def rb_next(self, node):
+        if not node:
+            return 0x0
+
+        right = self.rb_right(node)
+        if right:
+            return self.rb_first(right)
+
+        while True:
+            parent = self.rb_parent(node)
+            if not parent:
+                return 0x0
+
+            right = self.rb_right(parent)
+            if node != right:
+                return parent
+
+            node = parent
+
+    def __iter__(self):
+        return self.RbTreeIter(self)
+
+    class RbTreeIter(object):
+        def __init__(self, rbtree):
+            #pdb.set_trace()
+            self.rbtree = rbtree
+            node = rbtree.rd.read_structure_field(
+                        rbtree.rb_root, 'struct rb_root', 'rb_node')
+            self.cur = rbtree.rb_first(node)
+
+        def next(self):
+            if not self.cur:
+                raise StopIteration
+            self.cur = self.rbtree.rb_next(self.cur)
+            if not self.cur:
+                raise StopIteration
+            return self.cur
+
 
 class RbTreeWalker(object):
 
-- 
GitLab