diff options
Diffstat (limited to 'scripts/gdb')
| -rw-r--r-- | scripts/gdb/linux/Makefile | 2 | ||||
| -rw-r--r-- | scripts/gdb/linux/device.py | 182 | ||||
| -rw-r--r-- | scripts/gdb/linux/genpd.py | 83 | ||||
| -rw-r--r-- | scripts/gdb/vmlinux-gdb.py | 2 | 
4 files changed, 268 insertions, 1 deletions
| diff --git a/scripts/gdb/linux/Makefile b/scripts/gdb/linux/Makefile index 9fd3d8ed731a..124755087510 100644 --- a/scripts/gdb/linux/Makefile +++ b/scripts/gdb/linux/Makefile @@ -1,6 +1,6 @@  # SPDX-License-Identifier: GPL-2.0 -ifneq ($(srctree),.) +ifdef building_out_of_srctree  symlinks := $(patsubst $(srctree)/$(src)/%,%,$(wildcard $(srctree)/$(src)/*.py)) diff --git a/scripts/gdb/linux/device.py b/scripts/gdb/linux/device.py new file mode 100644 index 000000000000..16376c5cfec6 --- /dev/null +++ b/scripts/gdb/linux/device.py @@ -0,0 +1,182 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) NXP 2019 + +import gdb + +from linux.utils import CachedType +from linux.utils import container_of +from linux.lists import list_for_each_entry + + +device_private_type = CachedType('struct device_private') +device_type = CachedType('struct device') + +subsys_private_type = CachedType('struct subsys_private') +kobject_type = CachedType('struct kobject') +kset_type = CachedType('struct kset') + +bus_type = CachedType('struct bus_type') +class_type = CachedType('struct class') + + +def dev_name(dev): +    dev_init_name = dev['init_name'] +    if dev_init_name: +        return dev_init_name.string() +    return dev['kobj']['name'].string() + + +def kset_for_each_object(kset): +    return list_for_each_entry(kset['list'], +            kobject_type.get_type().pointer(), "entry") + + +def for_each_bus(): +    for kobj in kset_for_each_object(gdb.parse_and_eval('bus_kset')): +        subsys = container_of(kobj, kset_type.get_type().pointer(), 'kobj') +        subsys_priv = container_of(subsys, subsys_private_type.get_type().pointer(), 'subsys') +        yield subsys_priv['bus'] + + +def for_each_class(): +    for kobj in kset_for_each_object(gdb.parse_and_eval('class_kset')): +        subsys = container_of(kobj, kset_type.get_type().pointer(), 'kobj') +        subsys_priv = container_of(subsys, subsys_private_type.get_type().pointer(), 'subsys') +        yield subsys_priv['class'] + + +def get_bus_by_name(name): +    for item in for_each_bus(): +        if item['name'].string() == name: +            return item +    raise gdb.GdbError("Can't find bus type {!r}".format(name)) + + +def get_class_by_name(name): +    for item in for_each_class(): +        if item['name'].string() == name: +            return item +    raise gdb.GdbError("Can't find device class {!r}".format(name)) + + +klist_type = CachedType('struct klist') +klist_node_type = CachedType('struct klist_node') + + +def klist_for_each(klist): +    return list_for_each_entry(klist['k_list'], +                klist_node_type.get_type().pointer(), 'n_node') + + +def bus_for_each_device(bus): +    for kn in klist_for_each(bus['p']['klist_devices']): +        dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_bus') +        yield dp['device'] + + +def class_for_each_device(cls): +    for kn in klist_for_each(cls['p']['klist_devices']): +        dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_class') +        yield dp['device'] + + +def device_for_each_child(dev): +    for kn in klist_for_each(dev['p']['klist_children']): +        dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_parent') +        yield dp['device'] + + +def _show_device(dev, level=0, recursive=False): +    gdb.write('{}dev {}:\t{}\n'.format('\t' * level, dev_name(dev), dev)) +    if recursive: +        for child in device_for_each_child(dev): +            _show_device(child, level + 1, recursive) + + +class LxDeviceListBus(gdb.Command): +    '''Print devices on a bus (or all buses if not specified)''' + +    def __init__(self): +        super(LxDeviceListBus, self).__init__('lx-device-list-bus', gdb.COMMAND_DATA) + +    def invoke(self, arg, from_tty): +        if not arg: +            for bus in for_each_bus(): +                gdb.write('bus {}:\t{}\n'.format(bus['name'].string(), bus)) +                for dev in bus_for_each_device(bus): +                    _show_device(dev, level=1) +        else: +            bus = get_bus_by_name(arg) +            if not bus: +                raise gdb.GdbError("Can't find bus {!r}".format(arg)) +            for dev in bus_for_each_device(bus): +                _show_device(dev) + + +class LxDeviceListClass(gdb.Command): +    '''Print devices in a class (or all classes if not specified)''' + +    def __init__(self): +        super(LxDeviceListClass, self).__init__('lx-device-list-class', gdb.COMMAND_DATA) + +    def invoke(self, arg, from_tty): +        if not arg: +            for cls in for_each_class(): +                gdb.write("class {}:\t{}\n".format(cls['name'].string(), cls)) +                for dev in class_for_each_device(cls): +                    _show_device(dev, level=1) +        else: +            cls = get_class_by_name(arg) +            for dev in class_for_each_device(cls): +                _show_device(dev) + + +class LxDeviceListTree(gdb.Command): +    '''Print a device and its children recursively''' + +    def __init__(self): +        super(LxDeviceListTree, self).__init__('lx-device-list-tree', gdb.COMMAND_DATA) + +    def invoke(self, arg, from_tty): +        if not arg: +            raise gdb.GdbError('Please provide pointer to struct device') +        dev = gdb.parse_and_eval(arg) +        if dev.type != device_type.get_type().pointer(): +            raise gdb.GdbError('Please provide pointer to struct device') +        _show_device(dev, level=0, recursive=True) + + +class LxDeviceFindByBusName(gdb.Function): +    '''Find struct device by bus and name (both strings)''' + +    def __init__(self): +        super(LxDeviceFindByBusName, self).__init__('lx_device_find_by_bus_name') + +    def invoke(self, bus, name): +        name = name.string() +        bus = get_bus_by_name(bus.string()) +        for dev in bus_for_each_device(bus): +            if dev_name(dev) == name: +                return dev + + +class LxDeviceFindByClassName(gdb.Function): +    '''Find struct device by class and name (both strings)''' + +    def __init__(self): +        super(LxDeviceFindByClassName, self).__init__('lx_device_find_by_class_name') + +    def invoke(self, cls, name): +        name = name.string() +        cls = get_class_by_name(cls.string()) +        for dev in class_for_each_device(cls): +            if dev_name(dev) == name: +                return dev + + +LxDeviceListBus() +LxDeviceListClass() +LxDeviceListTree() +LxDeviceFindByBusName() +LxDeviceFindByClassName() diff --git a/scripts/gdb/linux/genpd.py b/scripts/gdb/linux/genpd.py new file mode 100644 index 000000000000..6ca93bd2949e --- /dev/null +++ b/scripts/gdb/linux/genpd.py @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) NXP 2019 + +import gdb +import sys + +from linux.utils import CachedType +from linux.lists import list_for_each_entry + +generic_pm_domain_type = CachedType('struct generic_pm_domain') +pm_domain_data_type = CachedType('struct pm_domain_data') +device_link_type = CachedType('struct device_link') + + +def kobject_get_path(kobj): +    path = kobj['name'].string() +    parent = kobj['parent'] +    if parent: +        path = kobject_get_path(parent) + '/' + path +    return path + + +def rtpm_status_str(dev): +    if dev['power']['runtime_error']: +        return 'error' +    if dev['power']['disable_depth']: +        return 'unsupported' +    _RPM_STATUS_LOOKUP = [ +        "active", +        "resuming", +        "suspended", +        "suspending" +    ] +    return _RPM_STATUS_LOOKUP[dev['power']['runtime_status']] + + +class LxGenPDSummary(gdb.Command): +    '''Print genpd summary + +Output is similar to /sys/kernel/debug/pm_genpd/pm_genpd_summary''' + +    def __init__(self): +        super(LxGenPDSummary, self).__init__('lx-genpd-summary', gdb.COMMAND_DATA) + +    def summary_one(self, genpd): +        if genpd['status'] == 0: +            status_string = 'on' +        else: +            status_string = 'off-{}'.format(genpd['state_idx']) + +        slave_names = [] +        for link in list_for_each_entry( +                genpd['master_links'], +                device_link_type.get_type().pointer(), +                'master_node'): +            slave_names.apend(link['slave']['name']) + +        gdb.write('%-30s  %-15s %s\n' % ( +                genpd['name'].string(), +                status_string, +                ', '.join(slave_names))) + +        # Print devices in domain +        for pm_data in list_for_each_entry(genpd['dev_list'], +                        pm_domain_data_type.get_type().pointer(), +                        'list_node'): +            dev = pm_data['dev'] +            kobj_path = kobject_get_path(dev['kobj']) +            gdb.write('    %-50s  %s\n' % (kobj_path, rtpm_status_str(dev))) + +    def invoke(self, arg, from_tty): +        gdb.write('domain                          status          slaves\n'); +        gdb.write('    /device                                             runtime status\n'); +        gdb.write('----------------------------------------------------------------------\n'); +        for genpd in list_for_each_entry( +                gdb.parse_and_eval('&gpd_list'), +                generic_pm_domain_type.get_type().pointer(), +                'gpd_list_node'): +            self.summary_one(genpd) + + +LxGenPDSummary() diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py index eff5a48ac026..4136dc2c59df 100644 --- a/scripts/gdb/vmlinux-gdb.py +++ b/scripts/gdb/vmlinux-gdb.py @@ -35,3 +35,5 @@ else:      import linux.constants      import linux.timerlist      import linux.clk +    import linux.genpd +    import linux.device | 
