tests/python/vdbtests.py
author Jan Vrany <jan.vrany@fit.cvut.cz>
Mon, 08 Jul 2019 13:31:11 +0100
changeset 178 5d1c3e5fab6b
parent 177 fd154978bab5
permissions -rw-r--r--
Initial support for VDB python-based variable objects Due to a limitation of GDB itself, one cannot create variable object for "synthetic" argument/local created by custom frame decorator. Therefore one cannot "dig deeper" and inspect contents of such a variable in case it is a kind of composite - like an object on a heap referring to another objects. This is a problem when a debugee is does not have debug information and / or it's language is not C - such as when debugging JITed code. This (experimental) commit adds a parallel implementation of variable objects done completely in python. This new varobj MI interface is a super-set of GDB's builtin varobj MI interface.

#
# jv:vdb - Visual / VM Debugger
# Copyright (C) 2015-now Jan Vrany
#
# This software is licensed under 'Creative Commons Attribution-NonCommercial 4.0 International License'
#
# You may find a full license text in LICENSE.txt or at http://creativecommons.org/licenses/by-nc/4.0/
#

"""
This script contains tests Pythin vdb support.
To run all tests

    gdb -q --ex "source vdbtests.py" -ex 'py run()' -ex "quit"

To run single test, for example, _instanceTests.test_context_03():

    gdb -q --ex "source vdbtests.py" -ex 'py run(parse_and_eval_test("test_01"))' -ex "quit"

"""

import os
import sys
import unittest

vdb_tests_python_dir = os.path.dirname(__file__)
vdb_python_dir = os.path.join(vdb_tests_python_dir, '..' , '..' , 'python')
libgdbs_tests_dir = os.path.join(vdb_python_dir, '..', '..' , 'libgdbs' , 'tests')

sys.path.append(vdb_python_dir)

import gdb
import vdb

class parse_and_eval_test(unittest.TestCase):
    def setUp(self):
        test_prog_dir = os.path.join(libgdbs_tests_dir, 'c', 'x86_64-pc-linux-gnu')

        gdb.execute('set startup-with-shell off')
        gdb.execute('set auto-load safe-path /')
        gdb.execute('set python print-stack full')
        gdb.execute('set breakpoint pending on')
        gdb.execute('set confirm off')
        gdb.execute('set pagination off')
        gdb.execute('file "%s"' % os.path.join(test_prog_dir, 'py-varobj'))
        gdb.execute('source %s' % os.path.join(test_prog_dir, '..', 'py-varobj.py'))
        gdb.execute('source %s' % os.path.join(test_prog_dir, '..', 'py-framedecorator.py'))
        gdb.execute('b py-varobj.c : 22')
        gdb.execute('r')
        gdb.execute('frame 0')


    def tearDown(self):
        vdb.unregister_evaluators()
        gdb.execute("del")
        try:
            gdb.execute('kill')
        except:
            pass

    def test_01a(self):
        self.assertRaises(vdb.Error, vdb.parse_and_eval, 'foo')
        self.assertEqual(gdb.Value(1), vdb.parse_and_eval('1'))

    def test_01b(self):
        v = vdb.parse_and_eval('&c1')
        self.assertEqual('struct _cons *', str(v.type))

    def test_01c(self):
        v = vdb.parse_and_eval('&c1')
        self.assertEqual('struct _cons *', str(v.type))

    def test_02a(self):
        self.assertEqual(gdb.Value(12), vdb.parse_and_eval('syntheticLocal0'))
        self.assertEqual(gdb.Value(42), vdb.parse_and_eval('syntheticLocal2'))

    def test_03(self):
        def parse_and_eval(expr):
            if expr == 'a':
                return gdb.Value(1)
            elif expr == 'b':
                return None
            elif expr == 'c':
                raise Exception("Bad")
        vdb.register_evaluator(parse_and_eval)

        self.assertEqual(gdb.Value(1), vdb.parse_and_eval('a'))

        self.assertRaises(vdb.Error, vdb.parse_and_eval, 'b')
        self.assertRaises(Exception, vdb.parse_and_eval, 'c')
        self.assertRaises(vdb.Error, vdb.parse_and_eval, 'd')

        vdb.unregister_evaluator(parse_and_eval)
        self.assertRaises(vdb.Error, vdb.parse_and_eval, 'a')



class VarObj_test(unittest.TestCase):
    def setUp(self):
        test_prog_dir = os.path.join(libgdbs_tests_dir, 'c', 'x86_64-pc-linux-gnu')

        gdb.execute('set startup-with-shell off')
        gdb.execute('set auto-load safe-path /')
        gdb.execute('set python print-stack full')
        gdb.execute('set breakpoint pending on')
        gdb.execute('set confirm off')
        gdb.execute('set pagination off')
        gdb.execute('file "%s"' % os.path.join(test_prog_dir, 'py-varobj'))
        gdb.execute('source %s' % os.path.join(test_prog_dir, '..', 'py-varobj.py'))
        gdb.execute('source %s' % os.path.join(test_prog_dir, '..', 'py-framedecorator.py'))
        gdb.execute('b py-varobj.c : 22')
        gdb.execute('r')
        gdb.execute('frame 0')

    def tearDown(self):
        vdb.unregister_evaluators()
        gdb.execute("del")
        try:
            gdb.execute('kill')
        except:
            pass

    def test_01(self):
        varobj = vdb._VarObj('test_01', '1', gdb.Value(1))
        self.assertEqual({  'name'      : 'test_01' ,
                            'numchild'  : 0,
                            'exp'       : '1',
                            'value'     : '1',
                            'type'      : 'long long',
                            'has_more'  : 0,
                            'dynamic'   : 1,
                            'frozen'    : 0
                            },
                         varobj.to_mi())

    def test_02(self):
        varobj = vdb._VarObj('test_02', '&c1', gdb.parse_and_eval('&c1'))
        self.assertEqual({  'name'      : 'test_02' ,
                            'numchild'  : 0,
                            'exp'       : '&c1',
                            'value'     : '(...)',
                            'type'      : 'struct _cons *',
                            'has_more'  : 1,
                            'dynamic'   : 1,
                            'frozen'    : 0
                            },
                         varobj.to_mi())
        children = list(varobj.children())
        self.assertEqual(2, len(children))
        self.assertEqual('car', children[0].exp)
        self.assertEqual('cdr', children[1].exp)

        self.assertEqual('test_02.car', children[0].name)
        self.assertEqual('test_02.cdr', children[1].name)

        self.assertEqual(varobj, children[0].parent)
        self.assertEqual(varobj, children[1].parent)

        children2 = list(varobj.children())
        self.assertEqual(children[0], children2[0])
        self.assertEqual(children[1], children2[1])

    def test_03(self):
        varobj = vdb._VarObj('test_02', '&c1', gdb.parse_and_eval('&c1'))
        children = list(varobj.children())
        self.assertEqual(2, len(children))

        varobj.set_visualizer(vdb._DefaultVisualizer(varobj._value))
        children = list(varobj.children())
        self.assertEqual(0, len(children))




class MI_test(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        vdb._VarObjs.unregister_all()

    def test_01(self):
        self.assertEqual({  'name'      : 'test_01' ,
                            'numchild'  : 0,
                            'exp'       : '1',
                            'value'     : '1',
                            'type'      : 'int',
                            'has_more'  : 0,
                            'dynamic'   : 1,
                            'frozen'    : 0
                            },
                         vdb._var_create(['test_01', '*' , '1']))
        self.assertEqual(None,
                         vdb._var_delete(['test_01']))


def run(test = None):
    if test == None:
        unittest.main()
    else:
        suite = unittest.TestSuite()
        suite.addTest(test)
        runner = unittest.TextTestRunner()
        runner.run(suite)