[kernel][debug] Elide 0s in hexdump

If there are consecutive rows which are entirely 0s when dumping memory,
elide all rows except the first row and the last row if that last row is
also the last row that will be dumped.

Change-Id: I39c2769b61e3a250d41ae19cbd73e58613fa6405
diff --git a/zircon/kernel/lib/debug/debug.cpp b/zircon/kernel/lib/debug/debug.cpp
index f5d8021..609c983 100644
--- a/zircon/kernel/lib/debug/debug.cpp
+++ b/zircon/kernel/lib/debug/debug.cpp
@@ -70,7 +70,8 @@
     addr_t address = (addr_t)ptr;
     size_t count;
 
-    for (count = 0; count < len; count += 16) {
+    int zero_line_count = 0;
+    for (count = 0; count < len; count += 16, address += 16) {
         union {
             uint32_t buf[4];
             uint8_t cbuf[16];
@@ -78,6 +79,24 @@
         size_t s = ROUNDUP(MIN(len - count, 16), 4);
         size_t i;
 
+        bool cur_line_zeros = true;
+        for (i = 0; i < s / 4; i++) {
+            cur_line_zeros &= (((const uint32_t*)address)[i] == 0);
+        }
+        if (cur_line_zeros) {
+            zero_line_count++;
+            if ((count + 16) >= len) {
+                // print the last line normally
+            } else if (zero_line_count >= 2) {
+                if (zero_line_count == 2) {
+                    pfn(".....\n");
+                }
+                continue;
+            }
+        } else {
+            zero_line_count = 0;
+        }
+
         pfn(((disp_addr + len) > 0xFFFFFFFF)
                 ? "0x%016llx: "
                 : "0x%08llx: ",
@@ -101,7 +120,6 @@
             }
         }
         pfn("|\n");
-        address += 16;
     }
 }
 
@@ -110,7 +128,26 @@
     size_t count;
     size_t i;
 
-    for (count = 0; count < len; count += 16) {
+    int zero_line_count = 0;
+    for (count = 0; count < len; count += 16, address += 16) {
+        bool cur_line_zeros = true;
+        for (i = 0; i < MIN(len - count, 16); i++) {
+            cur_line_zeros &= (((const uint8_t*)address)[i] == 0);
+        }
+        if (cur_line_zeros) {
+            zero_line_count++;
+            if ((count + 16) >= len) {
+                // print the last line normally
+            } else if (zero_line_count >= 2) {
+                if (zero_line_count == 2) {
+                    pfn(".....\n");
+                }
+                continue;
+            }
+        } else {
+            zero_line_count = 0;
+        }
+
         pfn(((disp_addr + len) > 0xFFFFFFFF)
                 ? "0x%016llx: "
                 : "0x%08llx: ",
@@ -132,7 +169,6 @@
         }
 
         pfn("\n");
-        address += 16;
     }
 }