From 97cff249d6730de7aa50fa06016fa1de1f587647 Mon Sep 17 00:00:00 2001
From: Mitchel Humpherys <mitchelh@codeaurora.org>
Date: Wed, 9 Apr 2014 15:16:55 -0700
Subject: [PATCH] lrdp-v2: add hexdump functions

It's useful to be able to dump regions of memory a la `xxd'. Add some
machinery to parser_util and RamDump to do this.

Example:

    $ ramparse.py -a . -o parsed --shell
    >>> dump.hexdump(0, 100, virtual=False)
    00000000: fffe ffde 0200 0000 ffff b7bf adf5 a5ff  ................
    00000010: e7bf edfe c6fe edf6 fefa fffe befa fefe  ................
    00000020: bfbe ffef aebd a5ef ffff 7f7e fefe 5afb  ...........~..Z.
    00000030: 1b00 2000 3300 4300 1c00 2100 3400 4800  .. .3.C...!.4.H.
    00000040: ffff ff7f fafe ffdb effd a5af adf5 a5bf  ................
    00000050: 4444 4444 4444 4444 4444 4444 4444 4444  DDDDDDDDDDDDDDDD
    00000060: 5fff ffff                                _...
    >>> dump.hexdump(0xc0000000, 100, virtual=True)
    c0000000: fffe ffde 0200 0000 ffff b7bf adf5 a5ff  ................
    c0000010: e7bf edfe c6fe edf6 fefa fffe befa fefe  ................
    c0000020: bfbe ffef aebd a5ef ffff 7f7e fefe 5afb  ...........~..Z.
    c0000030: 1b00 2000 3300 4300 1c00 2100 3400 4800  .. .3.C...!.4.H.
    c0000040: ffff ff7f fafe ffdb effd a5af adf5 a5bf  ................
    c0000050: 4444 4444 4444 4444 4444 4444 4444 4444  DDDDDDDDDDDDDDDD
    c0000060: 5fff ffff                                _...
    >>> dump.hexdump(dump.addr_lookup('linux_banner'), 144, virtual=True)
    c0b0006a: 4c69 6e75 7820 7665 7273 696f 6e20 332e  Linux version 3.
    c0b0007a: 3130 2e32 382d 6765 3232 3362 6632 3830  10.28-ge223bf280
    c0b0008a: 662d 6469 7274 7920 286d 6974 6368 656c  f-dirty (mitchel
    c0b0009a: 6840 6d69 7463 6865 6c68 2d6c 696e 7578  h@mitchelh-linux
    c0b000aa: 2920 2867 6363 2076 6572 7369 6f6e 2034  ) (gcc version 4
    c0b000ba: 2e37 2028 4743 4329 2029 2023 3720 534d  .7 (GCC) ) #7 SM
    c0b000ca: 5020 5052 4545 4d50 5420 5475 6520 4170  P PREEMPT Tue Ap
    c0b000da: 7220 3820 3134 3a32 303a 3132 2050 4454  r 8 14:20:12 PDT
    c0b000ea: 2032 3031 340a 007c 2f2d 5c00 0000 0000   2014..|/-\.....

Change-Id: Iecaf80f72845f052085a60eadedd2bb24743224c
---
 linux-ramdump-parser-v2/parser_util.py | 47 +++++++++++++++++++++++++-
 linux-ramdump-parser-v2/ramdump.py     | 16 +++++++--
 2 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/linux-ramdump-parser-v2/parser_util.py b/linux-ramdump-parser-v2/parser_util.py
index ae2449b..040f374 100644
--- a/linux-ramdump-parser-v2/parser_util.py
+++ b/linux-ramdump-parser-v2/parser_util.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+# Copyright (c) 2013-2014, 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
@@ -14,6 +14,7 @@ import platform
 import glob
 import re
 import string
+import sys
 
 _parsers = []
 
@@ -160,3 +161,47 @@ def get_system_type():
         return 'Linux'
     if plat == 'Darwin':
         return 'Darwin'
+
+def _get_printable(n, fillchar='.'):
+    if n is None:
+        return
+    c = chr(n)
+    if c in string.printable[:string.printable.index(' ') + 1]:
+        return c
+    return fillchar
+
+def _xxd_line(addr, data):
+    printable = [_get_printable(d) for d in data]
+    data = ['{:02x}'.format(d) for d in data]
+    printable += [' '] * (16 - len(printable))
+    data += ['  '] * (16 - len(data))
+    return "{:08x}: {:}{:} {:}{:} {:}{:} {:}{:} {:}{:} {:}{:} {:}{:} {:}{:}  {:}{:}{:}{:}{:}{:}{:}{:}{:}{:}{:}{:}{:}{:}{:}{:}\n".format(
+        addr, *(data + printable)
+    )
+
+def xxd(address, data, file_object=None):
+    """Dumps data to stdout, in the format of `xxd'. data should be a list
+    of integers.
+
+    >>> xxd(0x1000, [0xde, 0xad, 0xbe, 0xef, 112, 105, 122, 122, 97, 0, 0, 42, 43, 44, 45, 90])
+    00001000: dead beef 7069 7a7a 6100 002a 2b2c 2d5a  ....pizza..*+,-Z
+
+    """
+    f = file_object or sys.stdout
+    bb = []
+    n = 0
+    for i in data:
+        bb.append(i)
+        if n == 15:
+            f.write(_xxd_line(address, bb))
+            bb = []
+            n = 0
+            address += 16
+        else:
+            n += 1
+    if len(bb):
+        f.write(_xxd_line(address, bb))
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()
diff --git a/linux-ramdump-parser-v2/ramdump.py b/linux-ramdump-parser-v2/ramdump.py
index a24d364..8410eff 100644
--- a/linux-ramdump-parser-v2/ramdump.py
+++ b/linux-ramdump-parser-v2/ramdump.py
@@ -22,7 +22,7 @@ from tempfile import NamedTemporaryFile
 import gdbmi
 from print_out import print_out_str
 from mmu import Armv7MMU, Armv7LPAEMMU, Armv8MMU
-from parser_util import cleanupString
+import parser_util
 
 FP = 11
 SP = 13
@@ -975,7 +975,7 @@ class RamDump():
         ebi[0].seek(offset)
         a = ebi[0].read(length)
         if trace:
-            print_out_str('result = {0}'.format(cleanupString(a)))
+            print_out_str('result = {0}'.format(parser_util.cleanupString(a)))
             print_out_str('lenght = {0}'.format(len(a)))
         return a
 
@@ -1089,6 +1089,18 @@ class RamDump():
             return None
         return struct.unpack(format_string, s)
 
+    def hexdump(self, address, length, virtual=True, file_object=None):
+        """Does a hexdump (in the format of `xxd'). `length' is in bytes. If
+        given, will write to `file_object', otherwise will write to
+        stdout.
+
+        """
+        parser_util.xxd(
+            address,
+            [self.read_byte(address + i, virtual=virtual) or 0
+             for i in xrange(length)],
+            file_object=file_object)
+
     def per_cpu_offset(self, cpu):
         per_cpu_offset_addr = self.addr_lookup('__per_cpu_offset')
         if per_cpu_offset_addr is None:
-- 
GitLab