about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
authorFrank Busse <bb0xfb@gmail.com>2018-11-01 11:30:11 +0000
committerCristian Cadar <c.cadar@imperial.ac.uk>2018-12-19 22:22:27 +0000
commit8d953bdedcb3c004093bcc2fecb80c31397f2bcb (patch)
tree46b931acc87be4823ecd31ca934f93eddc5de5c6
parentbe1c91ace77d519c37348c290a2c03db159d01bf (diff)
downloadklee-8d953bdedcb3c004093bcc2fecb80c31397f2bcb.tar.gz
Various fixes for ktest-tool
* switch to Python 3
* add file encoding
* some PEP8 reformatting
* fix TOCTOU for open
* replace trimZeros() with rstrip
* remove unused pos/args variables
* remove --write-ints (print by default)
* remove progname section (unused)
* added/modified output rows
  - "data:" now shows the Python representation (for use in scripts)
  - "hex :" shows the hex representation
  - "text:" shows ASCII, all out-of-range/non-printable characters are replaced by a dot
  - "int :"/"uint:" print (unsigned) 8/16/32/64 bit integers
* reduce width for object counter to needed minimum instead of 4
* refactor printing into function
-rw-r--r--test/regression/2014-09-13-debug-info.c2
-rwxr-xr-xtools/ktest-tool/ktest-tool129
2 files changed, 75 insertions, 56 deletions
diff --git a/test/regression/2014-09-13-debug-info.c b/test/regression/2014-09-13-debug-info.c
index ddf8461d..e4e9874c 100644
--- a/test/regression/2014-09-13-debug-info.c
+++ b/test/regression/2014-09-13-debug-info.c
@@ -8,7 +8,7 @@
 // one with the prefered CEX. We verify this by using ktest-tool to dump the
 // values, and then checking the output.
 //
-// RUN: /bin/sh -c "ktest-tool --write-int %t.klee-out/*.ktest" | sort > %t.data-values
+// RUN: /bin/sh -c "ktest-tool %t.klee-out/*.ktest" | sort > %t.data-values
 // RUN: FileCheck < %t.data-values %s
 
 // CHECK: object 0: data: 0
diff --git a/tools/ktest-tool/ktest-tool b/tools/ktest-tool/ktest-tool
index b73c6375..fdea1e6a 100755
--- a/tools/ktest-tool/ktest-tool
+++ b/tools/ktest-tool/ktest-tool
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 
 # ===-- ktest-tool --------------------------------------------------------===##
 # 
@@ -9,25 +10,33 @@
 # 
 # ===----------------------------------------------------------------------===##
 
+import binascii
+import io
 import os
+import string
 import struct
 import sys
 
-version_no=3
+version_no = 3
+
 
 class KTestError(Exception):
     pass
 
+
 class KTest:
+    valid_chars = string.digits + string.ascii_letters + string.punctuation + ' '
+
     @staticmethod
     def fromfile(path):
-        if not os.path.exists(path):
-            print("ERROR: file %s not found" % (path))
+        try:
+            f = open(path, 'rb')
+        except IOError:
+            print("ERROR: file %s not found" % path)
             sys.exit(1)
-            
-        f = open(path,'rb')
+
         hdr = f.read(5)
-        if len(hdr)!=5 or (hdr!=b'KTEST' and hdr != b"BOUT\n"):
+        if len(hdr) != 5 or (hdr != b'KTEST' and hdr != b"BOUT\n"):
             raise KTestError('unrecognized file')
         version, = struct.unpack('>i', f.read(4))
         if version > version_no:
@@ -37,7 +46,7 @@ class KTest:
         for i in range(numArgs):
             size, = struct.unpack('>i', f.read(4))
             args.append(str(f.read(size).decode(encoding='ascii')))
-            
+
         if version >= 2:
             symArgvs, = struct.unpack('>i', f.read(4))
             symArgvLen, = struct.unpack('>i', f.read(4))
@@ -49,73 +58,83 @@ class KTest:
         objects = []
         for i in range(numObjects):
             size, = struct.unpack('>i', f.read(4))
-            name = f.read(size)
+            name = f.read(size).decode('utf-8')
             size, = struct.unpack('>i', f.read(4))
             bytes = f.read(size)
-            objects.append( (name,bytes) )
+            objects.append((name, bytes))
 
         # Create an instance
-        b = KTest(version, args, symArgvs, symArgvLen, objects)
-        # Augment with extra filename field
-        b.filename = path
+        b = KTest(version, path, args, symArgvs, symArgvLen, objects)
         return b
-    
-    def __init__(self, version, args, symArgvs, symArgvLen, objects):
+
+    def __init__(self, version, path, args, symArgvs, symArgvLen, objects):
         self.version = version
+        self.path = path
         self.symArgvs = symArgvs
         self.symArgvLen = symArgvLen
         self.args = args
         self.objects = objects
 
-        # add a field that represents the name of the program used to
-        # generate this .ktest file:
-        program_full_path = self.args[0]
-        program_name = os.path.basename(program_full_path)
-        # sometimes program names end in .bc, so strip them
-        if program_name.endswith('.bc'):
-          program_name = program_name[:-3]
-        self.programName = program_name
-        
-def trimZeros(str):
-    for i in range(len(str))[::-1]:
-        if str[i] != '\x00':
-            return str[:i+1]
-    return ''
-    
-def main(args):
+    def __format__(self, format_spec):
+        sio = io.StringIO()
+        width = str(len(str(max(1, len(self.objects) - 1))))
+
+        # print ktest info
+        print('ktest file : %r' % self.path, file=sio)
+        print('args       : %r' % self.args, file=sio)
+        print('num objects: %r' % len(self.objects), file=sio)
+
+        # format strings
+        fmt = dict()
+        fmt['name'] = "object {0:" + width + "d}: name: '{1}'"
+        fmt['size'] = "object {0:" + width + "d}: size: {1}"
+        fmt['int' ] = "object {0:" + width + "d}: int : {1}"
+        fmt['uint'] = "object {0:" + width + "d}: uint: {1}"
+        fmt['data'] = "object {0:" + width + "d}: data: {1}"
+        fmt['hex' ] = "object {0:" + width + "d}: hex : 0x{1}"
+        fmt['text'] = "object {0:" + width + "d}: text: {1}"
+
+        # print objects
+        for i, (name, data) in enumerate(self.objects):
+            def p(key, arg): print(fmt[key].format(i, arg), file=sio)
+
+            blob = data.rstrip(b'\x00') if format_spec.endswith('trimzeros') else data
+            txt = ''.join(c if c in self.valid_chars else '.' for c in blob.decode('ascii', errors='replace').replace('�', '.'))
+            size = len(data)
+
+            p('name', name)
+            p('size', size)
+            p('data', blob)
+            p('hex', binascii.hexlify(blob).decode('ascii'))
+            for n, m in [(1, 'b'), (2, 'h'), (4, 'i'), (8, 'q')]:
+                if size == n:
+                    p('int', struct.unpack(m, data)[0])
+                    p('uint', struct.unpack(m.upper(), data)[0])
+                    break
+            p('text', txt)
+
+        return sio.getvalue()
+
+
+def main():
     from optparse import OptionParser
     op = OptionParser("usage: %prog [options] files")
-    op.add_option('','--trim-zeros', dest='trimZeros', action='store_true', 
+    op.add_option('', '--trim-zeros', dest='trimZeros', action='store_true',
                   default=False,
                   help='trim trailing zeros')
-    op.add_option('','--write-ints', dest='writeInts', action='store_true',
-                  default=False,
-                  help='convert 4-byte sequences to integers')
-    
-    opts,args = op.parse_args()
+
+    opts, args = op.parse_args()
     if not args:
         op.error("incorrect number of arguments")
 
     for file in args:
-        b = KTest.fromfile(file)
-        pos = 0
-        print('ktest file : %r' % file)
-        print('args       : %r' % b.args)
-        print('num objects: %r' % len(b.objects))
-        for i,(name,data) in enumerate(b.objects):
-            if opts.trimZeros:
-                str = trimZeros(data)
-            else:
-                str = data
-
-            print('object %4d: name: %r' % (i, name))
-            print('object %4d: size: %r' % (i, len(data)))
-            if opts.writeInts and len(data) == 4: 
-                print('object %4d: data: %r' % (i, struct.unpack('i',str)[0]))
-            else:
-                print('object %4d: data: %r' % (i, str))
+        ktest = KTest.fromfile(file)
+        fmt = '{:trimzeros}' if opts.trimZeros else '{}'
+        print(fmt.format(ktest), end='')
+
         if file != args[-1]:
             print()
 
+
 if __name__=='__main__':
-    main(sys.argv)
+    main()