aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/gdb
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
committerWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
commita07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch)
tree84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /scripts/gdb
downloadohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz
ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'scripts/gdb')
-rw-r--r--scripts/gdb/Makefile2
-rw-r--r--scripts/gdb/linux/.gitignore4
-rw-r--r--scripts/gdb/linux/Makefile25
-rw-r--r--scripts/gdb/linux/__init__.py1
-rw-r--r--scripts/gdb/linux/clk.py76
-rw-r--r--scripts/gdb/linux/config.py44
-rw-r--r--scripts/gdb/linux/constants.py.in77
-rw-r--r--scripts/gdb/linux/cpus.py174
-rw-r--r--scripts/gdb/linux/device.py182
-rw-r--r--scripts/gdb/linux/dmesg.py154
-rw-r--r--scripts/gdb/linux/genpd.py83
-rw-r--r--scripts/gdb/linux/lists.py131
-rw-r--r--scripts/gdb/linux/modules.py95
-rw-r--r--scripts/gdb/linux/proc.py275
-rw-r--r--scripts/gdb/linux/rbtree.py177
-rw-r--r--scripts/gdb/linux/symbols.py187
-rw-r--r--scripts/gdb/linux/tasks.py140
-rw-r--r--scripts/gdb/linux/timerlist.py219
-rw-r--r--scripts/gdb/linux/utils.py193
-rw-r--r--scripts/gdb/vmlinux-gdb.py39
20 files changed, 2278 insertions, 0 deletions
diff --git a/scripts/gdb/Makefile b/scripts/gdb/Makefile
new file mode 100644
index 000000000..3fca1937d
--- /dev/null
+++ b/scripts/gdb/Makefile
@@ -0,0 +1,2 @@
1# SPDX-License-Identifier: GPL-2.0-only
2subdir-y := linux
diff --git a/scripts/gdb/linux/.gitignore b/scripts/gdb/linux/.gitignore
new file mode 100644
index 000000000..43234cbcb
--- /dev/null
+++ b/scripts/gdb/linux/.gitignore
@@ -0,0 +1,4 @@
1# SPDX-License-Identifier: GPL-2.0-only
2*.pyc
3*.pyo
4constants.py
diff --git a/scripts/gdb/linux/Makefile b/scripts/gdb/linux/Makefile
new file mode 100644
index 000000000..124755087
--- /dev/null
+++ b/scripts/gdb/linux/Makefile
@@ -0,0 +1,25 @@
1# SPDX-License-Identifier: GPL-2.0
2
3ifdef building_out_of_srctree
4
5symlinks := $(patsubst $(srctree)/$(src)/%,%,$(wildcard $(srctree)/$(src)/*.py))
6
7quiet_cmd_symlink = SYMLINK $@
8 cmd_symlink = ln -fsn $(patsubst $(obj)/%,$(abspath $(srctree))/$(src)/%,$@) $@
9
10extra-y += $(symlinks)
11$(addprefix $(obj)/, $(symlinks)): FORCE
12 $(call if_changed,symlink)
13
14endif
15
16quiet_cmd_gen_constants_py = GEN $@
17 cmd_gen_constants_py = \
18 $(CPP) -E -x c -P $(c_flags) $< > $@ ;\
19 sed -i '1,/<!-- end-c-headers -->/d;' $@
20
21extra-y += constants.py
22$(obj)/constants.py: $(src)/constants.py.in FORCE
23 $(call if_changed_dep,gen_constants_py)
24
25clean-files := *.pyc *.pyo
diff --git a/scripts/gdb/linux/__init__.py b/scripts/gdb/linux/__init__.py
new file mode 100644
index 000000000..4680fb176
--- /dev/null
+++ b/scripts/gdb/linux/__init__.py
@@ -0,0 +1 @@
# nothing to do for the initialization of this package
diff --git a/scripts/gdb/linux/clk.py b/scripts/gdb/linux/clk.py
new file mode 100644
index 000000000..061aecfa2
--- /dev/null
+++ b/scripts/gdb/linux/clk.py
@@ -0,0 +1,76 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Copyright (c) NXP 2019
4
5import gdb
6import sys
7
8from linux import utils, lists, constants
9
10clk_core_type = utils.CachedType("struct clk_core")
11
12
13def clk_core_for_each_child(hlist_head):
14 return lists.hlist_for_each_entry(hlist_head,
15 clk_core_type.get_type().pointer(), "child_node")
16
17
18class LxClkSummary(gdb.Command):
19 """Print clk tree summary
20
21Output is a subset of /sys/kernel/debug/clk/clk_summary
22
23No calls are made during printing, instead a (c) if printed after values which
24are cached and potentially out of date"""
25
26 def __init__(self):
27 super(LxClkSummary, self).__init__("lx-clk-summary", gdb.COMMAND_DATA)
28
29 def show_subtree(self, clk, level):
30 gdb.write("%*s%-*s %7d %8d %8d %11lu%s\n" % (
31 level * 3 + 1, "",
32 30 - level * 3,
33 clk['name'].string(),
34 clk['enable_count'],
35 clk['prepare_count'],
36 clk['protect_count'],
37 clk['rate'],
38 '(c)' if clk['flags'] & constants.LX_CLK_GET_RATE_NOCACHE else ' '))
39
40 for child in clk_core_for_each_child(clk['children']):
41 self.show_subtree(child, level + 1)
42
43 def invoke(self, arg, from_tty):
44 gdb.write(" enable prepare protect \n")
45 gdb.write(" clock count count count rate \n")
46 gdb.write("------------------------------------------------------------------------\n")
47 for clk in clk_core_for_each_child(gdb.parse_and_eval("clk_root_list")):
48 self.show_subtree(clk, 0)
49 for clk in clk_core_for_each_child(gdb.parse_and_eval("clk_orphan_list")):
50 self.show_subtree(clk, 0)
51
52
53LxClkSummary()
54
55
56class LxClkCoreLookup(gdb.Function):
57 """Find struct clk_core by name"""
58
59 def __init__(self):
60 super(LxClkCoreLookup, self).__init__("lx_clk_core_lookup")
61
62 def lookup_hlist(self, hlist_head, name):
63 for child in clk_core_for_each_child(hlist_head):
64 if child['name'].string() == name:
65 return child
66 result = self.lookup_hlist(child['children'], name)
67 if result:
68 return result
69
70 def invoke(self, name):
71 name = name.string()
72 return (self.lookup_hlist(gdb.parse_and_eval("clk_root_list"), name) or
73 self.lookup_hlist(gdb.parse_and_eval("clk_orphan_list"), name))
74
75
76LxClkCoreLookup()
diff --git a/scripts/gdb/linux/config.py b/scripts/gdb/linux/config.py
new file mode 100644
index 000000000..8843ab3cb
--- /dev/null
+++ b/scripts/gdb/linux/config.py
@@ -0,0 +1,44 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Copyright 2019 Google LLC.
4
5import gdb
6import zlib
7
8from linux import utils
9
10
11class LxConfigDump(gdb.Command):
12 """Output kernel config to the filename specified as the command
13 argument. Equivalent to 'zcat /proc/config.gz > config.txt' on
14 a running target"""
15
16 def __init__(self):
17 super(LxConfigDump, self).__init__("lx-configdump", gdb.COMMAND_DATA,
18 gdb.COMPLETE_FILENAME)
19
20 def invoke(self, arg, from_tty):
21 if len(arg) == 0:
22 filename = "config.txt"
23 else:
24 filename = arg
25
26 try:
27 py_config_ptr = gdb.parse_and_eval("&kernel_config_data")
28 py_config_ptr_end = gdb.parse_and_eval("&kernel_config_data_end")
29 py_config_size = py_config_ptr_end - py_config_ptr
30 except gdb.error as e:
31 raise gdb.GdbError("Can't find config, enable CONFIG_IKCONFIG?")
32
33 inf = gdb.inferiors()[0]
34 zconfig_buf = utils.read_memoryview(inf, py_config_ptr,
35 py_config_size).tobytes()
36
37 config_buf = zlib.decompress(zconfig_buf, 16)
38 with open(filename, 'wb') as f:
39 f.write(config_buf)
40
41 gdb.write("Dumped config to " + filename + "\n")
42
43
44LxConfigDump()
diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
new file mode 100644
index 000000000..2efbec6b6
--- /dev/null
+++ b/scripts/gdb/linux/constants.py.in
@@ -0,0 +1,77 @@
1/*
2 * gdb helper commands and functions for Linux kernel debugging
3 *
4 * Kernel constants derived from include files.
5 *
6 * Copyright (c) 2016 Linaro Ltd
7 *
8 * Authors:
9 * Kieran Bingham <kieran.bingham@linaro.org>
10 *
11 * This work is licensed under the terms of the GNU GPL version 2.
12 *
13 */
14
15#include <linux/clk-provider.h>
16#include <linux/fs.h>
17#include <linux/hrtimer.h>
18#include <linux/mount.h>
19#include <linux/of_fdt.h>
20#include <linux/threads.h>
21
22/* We need to stringify expanded macros so that they can be parsed */
23
24#define STRING(x) #x
25#define XSTRING(x) STRING(x)
26
27#define LX_VALUE(x) LX_##x = x
28#define LX_GDBPARSED(x) LX_##x = gdb.parse_and_eval(XSTRING(x))
29
30/*
31 * IS_ENABLED generates (a || b) which is not compatible with python
32 * We can only switch on configuration items we know are available
33 * Therefore - IS_BUILTIN() is more appropriate
34 */
35#define LX_CONFIG(x) LX_##x = IS_BUILTIN(x)
36
37/* The build system will take care of deleting everything above this marker */
38<!-- end-c-headers -->
39
40import gdb
41
42/* linux/clk-provider.h */
43if IS_BUILTIN(CONFIG_COMMON_CLK):
44 LX_GDBPARSED(CLK_GET_RATE_NOCACHE)
45
46/* linux/fs.h */
47LX_VALUE(SB_RDONLY)
48LX_VALUE(SB_SYNCHRONOUS)
49LX_VALUE(SB_MANDLOCK)
50LX_VALUE(SB_DIRSYNC)
51LX_VALUE(SB_NOATIME)
52LX_VALUE(SB_NODIRATIME)
53
54/* linux/htimer.h */
55LX_GDBPARSED(hrtimer_resolution)
56
57/* linux/mount.h */
58LX_VALUE(MNT_NOSUID)
59LX_VALUE(MNT_NODEV)
60LX_VALUE(MNT_NOEXEC)
61LX_VALUE(MNT_NOATIME)
62LX_VALUE(MNT_NODIRATIME)
63LX_VALUE(MNT_RELATIME)
64
65/* linux/threads.h */
66LX_VALUE(NR_CPUS)
67
68/* linux/of_fdt.h> */
69LX_VALUE(OF_DT_HEADER)
70
71/* Kernel Configs */
72LX_CONFIG(CONFIG_GENERIC_CLOCKEVENTS)
73LX_CONFIG(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
74LX_CONFIG(CONFIG_HIGH_RES_TIMERS)
75LX_CONFIG(CONFIG_NR_CPUS)
76LX_CONFIG(CONFIG_OF)
77LX_CONFIG(CONFIG_TICK_ONESHOT)
diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py
new file mode 100644
index 000000000..008e62f31
--- /dev/null
+++ b/scripts/gdb/linux/cpus.py
@@ -0,0 +1,174 @@
1#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# per-cpu tools
5#
6# Copyright (c) Siemens AG, 2011-2013
7#
8# Authors:
9# Jan Kiszka <jan.kiszka@siemens.com>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import gdb
15
16from linux import tasks, utils
17
18
19MAX_CPUS = 4096
20
21
22def get_current_cpu():
23 if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU:
24 return gdb.selected_thread().num - 1
25 elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB:
26 tid = gdb.selected_thread().ptid[2]
27 if tid > (0x100000000 - MAX_CPUS - 2):
28 return 0x100000000 - tid - 2
29 else:
30 return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu']
31 else:
32 raise gdb.GdbError("Sorry, obtaining the current CPU is not yet "
33 "supported with this gdb server.")
34
35
36def per_cpu(var_ptr, cpu):
37 if cpu == -1:
38 cpu = get_current_cpu()
39 if utils.is_target_arch("sparc:v9"):
40 offset = gdb.parse_and_eval(
41 "trap_block[{0}].__per_cpu_base".format(str(cpu)))
42 else:
43 try:
44 offset = gdb.parse_and_eval(
45 "__per_cpu_offset[{0}]".format(str(cpu)))
46 except gdb.error:
47 # !CONFIG_SMP case
48 offset = 0
49 pointer = var_ptr.cast(utils.get_long_type()) + offset
50 return pointer.cast(var_ptr.type).dereference()
51
52
53cpu_mask = {}
54
55
56def cpu_mask_invalidate(event):
57 global cpu_mask
58 cpu_mask = {}
59 gdb.events.stop.disconnect(cpu_mask_invalidate)
60 if hasattr(gdb.events, 'new_objfile'):
61 gdb.events.new_objfile.disconnect(cpu_mask_invalidate)
62
63
64def cpu_list(mask_name):
65 global cpu_mask
66 mask = None
67 if mask_name in cpu_mask:
68 mask = cpu_mask[mask_name]
69 if mask is None:
70 mask = gdb.parse_and_eval(mask_name + ".bits")
71 if hasattr(gdb, 'events'):
72 cpu_mask[mask_name] = mask
73 gdb.events.stop.connect(cpu_mask_invalidate)
74 if hasattr(gdb.events, 'new_objfile'):
75 gdb.events.new_objfile.connect(cpu_mask_invalidate)
76 bits_per_entry = mask[0].type.sizeof * 8
77 num_entries = mask.type.sizeof * 8 / bits_per_entry
78 entry = -1
79 bits = 0
80
81 while True:
82 while bits == 0:
83 entry += 1
84 if entry == num_entries:
85 return
86 bits = mask[entry]
87 if bits != 0:
88 bit = 0
89 break
90
91 while bits & 1 == 0:
92 bits >>= 1
93 bit += 1
94
95 cpu = entry * bits_per_entry + bit
96
97 bits >>= 1
98 bit += 1
99
100 yield int(cpu)
101
102
103def each_online_cpu():
104 for cpu in cpu_list("__cpu_online_mask"):
105 yield cpu
106
107
108def each_present_cpu():
109 for cpu in cpu_list("__cpu_present_mask"):
110 yield cpu
111
112
113def each_possible_cpu():
114 for cpu in cpu_list("__cpu_possible_mask"):
115 yield cpu
116
117
118def each_active_cpu():
119 for cpu in cpu_list("__cpu_active_mask"):
120 yield cpu
121
122
123class LxCpus(gdb.Command):
124 """List CPU status arrays
125
126Displays the known state of each CPU based on the kernel masks
127and can help identify the state of hotplugged CPUs"""
128
129 def __init__(self):
130 super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA)
131
132 def invoke(self, arg, from_tty):
133 gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu())))
134 gdb.write("Present CPUs : {}\n".format(list(each_present_cpu())))
135 gdb.write("Online CPUs : {}\n".format(list(each_online_cpu())))
136 gdb.write("Active CPUs : {}\n".format(list(each_active_cpu())))
137
138
139LxCpus()
140
141
142class PerCpu(gdb.Function):
143 """Return per-cpu variable.
144
145$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the
146given CPU number. If CPU is omitted, the CPU of the current context is used.
147Note that VAR has to be quoted as string."""
148
149 def __init__(self):
150 super(PerCpu, self).__init__("lx_per_cpu")
151
152 def invoke(self, var_name, cpu=-1):
153 var_ptr = gdb.parse_and_eval("&" + var_name.string())
154 return per_cpu(var_ptr, cpu)
155
156
157PerCpu()
158
159
160class LxCurrentFunc(gdb.Function):
161 """Return current task.
162
163$lx_current([CPU]): Return the per-cpu task variable for the given CPU
164number. If CPU is omitted, the CPU of the current context is used."""
165
166 def __init__(self):
167 super(LxCurrentFunc, self).__init__("lx_current")
168
169 def invoke(self, cpu=-1):
170 var_ptr = gdb.parse_and_eval("&current_task")
171 return per_cpu(var_ptr, cpu).dereference()
172
173
174LxCurrentFunc()
diff --git a/scripts/gdb/linux/device.py b/scripts/gdb/linux/device.py
new file mode 100644
index 000000000..16376c5cf
--- /dev/null
+++ b/scripts/gdb/linux/device.py
@@ -0,0 +1,182 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Copyright (c) NXP 2019
4
5import gdb
6
7from linux.utils import CachedType
8from linux.utils import container_of
9from linux.lists import list_for_each_entry
10
11
12device_private_type = CachedType('struct device_private')
13device_type = CachedType('struct device')
14
15subsys_private_type = CachedType('struct subsys_private')
16kobject_type = CachedType('struct kobject')
17kset_type = CachedType('struct kset')
18
19bus_type = CachedType('struct bus_type')
20class_type = CachedType('struct class')
21
22
23def dev_name(dev):
24 dev_init_name = dev['init_name']
25 if dev_init_name:
26 return dev_init_name.string()
27 return dev['kobj']['name'].string()
28
29
30def kset_for_each_object(kset):
31 return list_for_each_entry(kset['list'],
32 kobject_type.get_type().pointer(), "entry")
33
34
35def for_each_bus():
36 for kobj in kset_for_each_object(gdb.parse_and_eval('bus_kset')):
37 subsys = container_of(kobj, kset_type.get_type().pointer(), 'kobj')
38 subsys_priv = container_of(subsys, subsys_private_type.get_type().pointer(), 'subsys')
39 yield subsys_priv['bus']
40
41
42def for_each_class():
43 for kobj in kset_for_each_object(gdb.parse_and_eval('class_kset')):
44 subsys = container_of(kobj, kset_type.get_type().pointer(), 'kobj')
45 subsys_priv = container_of(subsys, subsys_private_type.get_type().pointer(), 'subsys')
46 yield subsys_priv['class']
47
48
49def get_bus_by_name(name):
50 for item in for_each_bus():
51 if item['name'].string() == name:
52 return item
53 raise gdb.GdbError("Can't find bus type {!r}".format(name))
54
55
56def get_class_by_name(name):
57 for item in for_each_class():
58 if item['name'].string() == name:
59 return item
60 raise gdb.GdbError("Can't find device class {!r}".format(name))
61
62
63klist_type = CachedType('struct klist')
64klist_node_type = CachedType('struct klist_node')
65
66
67def klist_for_each(klist):
68 return list_for_each_entry(klist['k_list'],
69 klist_node_type.get_type().pointer(), 'n_node')
70
71
72def bus_for_each_device(bus):
73 for kn in klist_for_each(bus['p']['klist_devices']):
74 dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_bus')
75 yield dp['device']
76
77
78def class_for_each_device(cls):
79 for kn in klist_for_each(cls['p']['klist_devices']):
80 dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_class')
81 yield dp['device']
82
83
84def device_for_each_child(dev):
85 for kn in klist_for_each(dev['p']['klist_children']):
86 dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_parent')
87 yield dp['device']
88
89
90def _show_device(dev, level=0, recursive=False):
91 gdb.write('{}dev {}:\t{}\n'.format('\t' * level, dev_name(dev), dev))
92 if recursive:
93 for child in device_for_each_child(dev):
94 _show_device(child, level + 1, recursive)
95
96
97class LxDeviceListBus(gdb.Command):
98 '''Print devices on a bus (or all buses if not specified)'''
99
100 def __init__(self):
101 super(LxDeviceListBus, self).__init__('lx-device-list-bus', gdb.COMMAND_DATA)
102
103 def invoke(self, arg, from_tty):
104 if not arg:
105 for bus in for_each_bus():
106 gdb.write('bus {}:\t{}\n'.format(bus['name'].string(), bus))
107 for dev in bus_for_each_device(bus):
108 _show_device(dev, level=1)
109 else:
110 bus = get_bus_by_name(arg)
111 if not bus:
112 raise gdb.GdbError("Can't find bus {!r}".format(arg))
113 for dev in bus_for_each_device(bus):
114 _show_device(dev)
115
116
117class LxDeviceListClass(gdb.Command):
118 '''Print devices in a class (or all classes if not specified)'''
119
120 def __init__(self):
121 super(LxDeviceListClass, self).__init__('lx-device-list-class', gdb.COMMAND_DATA)
122
123 def invoke(self, arg, from_tty):
124 if not arg:
125 for cls in for_each_class():
126 gdb.write("class {}:\t{}\n".format(cls['name'].string(), cls))
127 for dev in class_for_each_device(cls):
128 _show_device(dev, level=1)
129 else:
130 cls = get_class_by_name(arg)
131 for dev in class_for_each_device(cls):
132 _show_device(dev)
133
134
135class LxDeviceListTree(gdb.Command):
136 '''Print a device and its children recursively'''
137
138 def __init__(self):
139 super(LxDeviceListTree, self).__init__('lx-device-list-tree', gdb.COMMAND_DATA)
140
141 def invoke(self, arg, from_tty):
142 if not arg:
143 raise gdb.GdbError('Please provide pointer to struct device')
144 dev = gdb.parse_and_eval(arg)
145 if dev.type != device_type.get_type().pointer():
146 raise gdb.GdbError('Please provide pointer to struct device')
147 _show_device(dev, level=0, recursive=True)
148
149
150class LxDeviceFindByBusName(gdb.Function):
151 '''Find struct device by bus and name (both strings)'''
152
153 def __init__(self):
154 super(LxDeviceFindByBusName, self).__init__('lx_device_find_by_bus_name')
155
156 def invoke(self, bus, name):
157 name = name.string()
158 bus = get_bus_by_name(bus.string())
159 for dev in bus_for_each_device(bus):
160 if dev_name(dev) == name:
161 return dev
162
163
164class LxDeviceFindByClassName(gdb.Function):
165 '''Find struct device by class and name (both strings)'''
166
167 def __init__(self):
168 super(LxDeviceFindByClassName, self).__init__('lx_device_find_by_class_name')
169
170 def invoke(self, cls, name):
171 name = name.string()
172 cls = get_class_by_name(cls.string())
173 for dev in class_for_each_device(cls):
174 if dev_name(dev) == name:
175 return dev
176
177
178LxDeviceListBus()
179LxDeviceListClass()
180LxDeviceListTree()
181LxDeviceFindByBusName()
182LxDeviceFindByClassName()
diff --git a/scripts/gdb/linux/dmesg.py b/scripts/gdb/linux/dmesg.py
new file mode 100644
index 000000000..a92c55bd8
--- /dev/null
+++ b/scripts/gdb/linux/dmesg.py
@@ -0,0 +1,154 @@
1#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# kernel log buffer dump
5#
6# Copyright (c) Siemens AG, 2011, 2012
7#
8# Authors:
9# Jan Kiszka <jan.kiszka@siemens.com>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import gdb
15import sys
16
17from linux import utils
18
19printk_info_type = utils.CachedType("struct printk_info")
20prb_data_blk_lpos_type = utils.CachedType("struct prb_data_blk_lpos")
21prb_desc_type = utils.CachedType("struct prb_desc")
22prb_desc_ring_type = utils.CachedType("struct prb_desc_ring")
23prb_data_ring_type = utils.CachedType("struct prb_data_ring")
24printk_ringbuffer_type = utils.CachedType("struct printk_ringbuffer")
25atomic_long_type = utils.CachedType("atomic_long_t")
26
27class LxDmesg(gdb.Command):
28 """Print Linux kernel log buffer."""
29
30 def __init__(self):
31 super(LxDmesg, self).__init__("lx-dmesg", gdb.COMMAND_DATA)
32
33 def invoke(self, arg, from_tty):
34 inf = gdb.inferiors()[0]
35
36 # read in prb structure
37 prb_addr = int(str(gdb.parse_and_eval("(void *)'printk.c'::prb")).split()[0], 16)
38 sz = printk_ringbuffer_type.get_type().sizeof
39 prb = utils.read_memoryview(inf, prb_addr, sz).tobytes()
40
41 # read in descriptor ring structure
42 off = printk_ringbuffer_type.get_type()['desc_ring'].bitpos // 8
43 addr = prb_addr + off
44 sz = prb_desc_ring_type.get_type().sizeof
45 desc_ring = utils.read_memoryview(inf, addr, sz).tobytes()
46
47 # read in descriptor array
48 off = prb_desc_ring_type.get_type()['count_bits'].bitpos // 8
49 desc_ring_count = 1 << utils.read_u32(desc_ring, off)
50 desc_sz = prb_desc_type.get_type().sizeof
51 off = prb_desc_ring_type.get_type()['descs'].bitpos // 8
52 addr = utils.read_ulong(desc_ring, off)
53 descs = utils.read_memoryview(inf, addr, desc_sz * desc_ring_count).tobytes()
54
55 # read in info array
56 info_sz = printk_info_type.get_type().sizeof
57 off = prb_desc_ring_type.get_type()['infos'].bitpos // 8
58 addr = utils.read_ulong(desc_ring, off)
59 infos = utils.read_memoryview(inf, addr, info_sz * desc_ring_count).tobytes()
60
61 # read in text data ring structure
62 off = printk_ringbuffer_type.get_type()['text_data_ring'].bitpos // 8
63 addr = prb_addr + off
64 sz = prb_data_ring_type.get_type().sizeof
65 text_data_ring = utils.read_memoryview(inf, addr, sz).tobytes()
66
67 # read in text data
68 off = prb_data_ring_type.get_type()['size_bits'].bitpos // 8
69 text_data_sz = 1 << utils.read_u32(text_data_ring, off)
70 off = prb_data_ring_type.get_type()['data'].bitpos // 8
71 addr = utils.read_ulong(text_data_ring, off)
72 text_data = utils.read_memoryview(inf, addr, text_data_sz).tobytes()
73
74 counter_off = atomic_long_type.get_type()['counter'].bitpos // 8
75
76 sv_off = prb_desc_type.get_type()['state_var'].bitpos // 8
77
78 off = prb_desc_type.get_type()['text_blk_lpos'].bitpos // 8
79 begin_off = off + (prb_data_blk_lpos_type.get_type()['begin'].bitpos // 8)
80 next_off = off + (prb_data_blk_lpos_type.get_type()['next'].bitpos // 8)
81
82 ts_off = printk_info_type.get_type()['ts_nsec'].bitpos // 8
83 len_off = printk_info_type.get_type()['text_len'].bitpos // 8
84
85 # definitions from kernel/printk/printk_ringbuffer.h
86 desc_committed = 1
87 desc_finalized = 2
88 desc_sv_bits = utils.get_long_type().sizeof * 8
89 desc_flags_shift = desc_sv_bits - 2
90 desc_flags_mask = 3 << desc_flags_shift
91 desc_id_mask = ~desc_flags_mask
92
93 # read in tail and head descriptor ids
94 off = prb_desc_ring_type.get_type()['tail_id'].bitpos // 8
95 tail_id = utils.read_u64(desc_ring, off + counter_off)
96 off = prb_desc_ring_type.get_type()['head_id'].bitpos // 8
97 head_id = utils.read_u64(desc_ring, off + counter_off)
98
99 did = tail_id
100 while True:
101 ind = did % desc_ring_count
102 desc_off = desc_sz * ind
103 info_off = info_sz * ind
104
105 # skip non-committed record
106 state = 3 & (utils.read_u64(descs, desc_off + sv_off +
107 counter_off) >> desc_flags_shift)
108 if state != desc_committed and state != desc_finalized:
109 if did == head_id:
110 break
111 did = (did + 1) & desc_id_mask
112 continue
113
114 begin = utils.read_ulong(descs, desc_off + begin_off) % text_data_sz
115 end = utils.read_ulong(descs, desc_off + next_off) % text_data_sz
116
117 # handle data-less record
118 if begin & 1 == 1:
119 text = ""
120 else:
121 # handle wrapping data block
122 if begin > end:
123 begin = 0
124
125 # skip over descriptor id
126 text_start = begin + utils.get_long_type().sizeof
127
128 text_len = utils.read_u16(infos, info_off + len_off)
129
130 # handle truncated message
131 if end - text_start < text_len:
132 text_len = end - text_start
133
134 text = text_data[text_start:text_start + text_len].decode(
135 encoding='utf8', errors='replace')
136
137 time_stamp = utils.read_u64(infos, info_off + ts_off)
138
139 for line in text.splitlines():
140 msg = u"[{time:12.6f}] {line}\n".format(
141 time=time_stamp / 1000000000.0,
142 line=line)
143 # With python2 gdb.write will attempt to convert unicode to
144 # ascii and might fail so pass an utf8-encoded str instead.
145 if sys.hexversion < 0x03000000:
146 msg = msg.encode(encoding='utf8', errors='replace')
147 gdb.write(msg)
148
149 if did == head_id:
150 break
151 did = (did + 1) & desc_id_mask
152
153
154LxDmesg()
diff --git a/scripts/gdb/linux/genpd.py b/scripts/gdb/linux/genpd.py
new file mode 100644
index 000000000..39cd1abd8
--- /dev/null
+++ b/scripts/gdb/linux/genpd.py
@@ -0,0 +1,83 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Copyright (c) NXP 2019
4
5import gdb
6import sys
7
8from linux.utils import CachedType
9from linux.lists import list_for_each_entry
10
11generic_pm_domain_type = CachedType('struct generic_pm_domain')
12pm_domain_data_type = CachedType('struct pm_domain_data')
13device_link_type = CachedType('struct device_link')
14
15
16def kobject_get_path(kobj):
17 path = kobj['name'].string()
18 parent = kobj['parent']
19 if parent:
20 path = kobject_get_path(parent) + '/' + path
21 return path
22
23
24def rtpm_status_str(dev):
25 if dev['power']['runtime_error']:
26 return 'error'
27 if dev['power']['disable_depth']:
28 return 'unsupported'
29 _RPM_STATUS_LOOKUP = [
30 "active",
31 "resuming",
32 "suspended",
33 "suspending"
34 ]
35 return _RPM_STATUS_LOOKUP[dev['power']['runtime_status']]
36
37
38class LxGenPDSummary(gdb.Command):
39 '''Print genpd summary
40
41Output is similar to /sys/kernel/debug/pm_genpd/pm_genpd_summary'''
42
43 def __init__(self):
44 super(LxGenPDSummary, self).__init__('lx-genpd-summary', gdb.COMMAND_DATA)
45
46 def summary_one(self, genpd):
47 if genpd['status'] == 0:
48 status_string = 'on'
49 else:
50 status_string = 'off-{}'.format(genpd['state_idx'])
51
52 child_names = []
53 for link in list_for_each_entry(
54 genpd['parent_links'],
55 device_link_type.get_type().pointer(),
56 'parent_node'):
57 child_names.append(link['child']['name'])
58
59 gdb.write('%-30s %-15s %s\n' % (
60 genpd['name'].string(),
61 status_string,
62 ', '.join(child_names)))
63
64 # Print devices in domain
65 for pm_data in list_for_each_entry(genpd['dev_list'],
66 pm_domain_data_type.get_type().pointer(),
67 'list_node'):
68 dev = pm_data['dev']
69 kobj_path = kobject_get_path(dev['kobj'])
70 gdb.write(' %-50s %s\n' % (kobj_path, rtpm_status_str(dev)))
71
72 def invoke(self, arg, from_tty):
73 gdb.write('domain status children\n');
74 gdb.write(' /device runtime status\n');
75 gdb.write('----------------------------------------------------------------------\n');
76 for genpd in list_for_each_entry(
77 gdb.parse_and_eval('&gpd_list'),
78 generic_pm_domain_type.get_type().pointer(),
79 'gpd_list_node'):
80 self.summary_one(genpd)
81
82
83LxGenPDSummary()
diff --git a/scripts/gdb/linux/lists.py b/scripts/gdb/linux/lists.py
new file mode 100644
index 000000000..c487ddf09
--- /dev/null
+++ b/scripts/gdb/linux/lists.py
@@ -0,0 +1,131 @@
1#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# list tools
5#
6# Copyright (c) Thiebaud Weksteen, 2015
7#
8# Authors:
9# Thiebaud Weksteen <thiebaud@weksteen.fr>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import gdb
15
16from linux import utils
17
18list_head = utils.CachedType("struct list_head")
19hlist_head = utils.CachedType("struct hlist_head")
20hlist_node = utils.CachedType("struct hlist_node")
21
22
23def list_for_each(head):
24 if head.type == list_head.get_type().pointer():
25 head = head.dereference()
26 elif head.type != list_head.get_type():
27 raise TypeError("Must be struct list_head not {}"
28 .format(head.type))
29
30 node = head['next'].dereference()
31 while node.address != head.address:
32 yield node.address
33 node = node['next'].dereference()
34
35
36def list_for_each_entry(head, gdbtype, member):
37 for node in list_for_each(head):
38 yield utils.container_of(node, gdbtype, member)
39
40
41def hlist_for_each(head):
42 if head.type == hlist_head.get_type().pointer():
43 head = head.dereference()
44 elif head.type != hlist_head.get_type():
45 raise TypeError("Must be struct hlist_head not {}"
46 .format(head.type))
47
48 node = head['first'].dereference()
49 while node.address:
50 yield node.address
51 node = node['next'].dereference()
52
53
54def hlist_for_each_entry(head, gdbtype, member):
55 for node in hlist_for_each(head):
56 yield utils.container_of(node, gdbtype, member)
57
58
59def list_check(head):
60 nb = 0
61 if (head.type == list_head.get_type().pointer()):
62 head = head.dereference()
63 elif (head.type != list_head.get_type()):
64 raise gdb.GdbError('argument must be of type (struct list_head [*])')
65 c = head
66 try:
67 gdb.write("Starting with: {}\n".format(c))
68 except gdb.MemoryError:
69 gdb.write('head is not accessible\n')
70 return
71 while True:
72 p = c['prev'].dereference()
73 n = c['next'].dereference()
74 try:
75 if p['next'] != c.address:
76 gdb.write('prev.next != current: '
77 'current@{current_addr}={current} '
78 'prev@{p_addr}={p}\n'.format(
79 current_addr=c.address,
80 current=c,
81 p_addr=p.address,
82 p=p,
83 ))
84 return
85 except gdb.MemoryError:
86 gdb.write('prev is not accessible: '
87 'current@{current_addr}={current}\n'.format(
88 current_addr=c.address,
89 current=c
90 ))
91 return
92 try:
93 if n['prev'] != c.address:
94 gdb.write('next.prev != current: '
95 'current@{current_addr}={current} '
96 'next@{n_addr}={n}\n'.format(
97 current_addr=c.address,
98 current=c,
99 n_addr=n.address,
100 n=n,
101 ))
102 return
103 except gdb.MemoryError:
104 gdb.write('next is not accessible: '
105 'current@{current_addr}={current}\n'.format(
106 current_addr=c.address,
107 current=c
108 ))
109 return
110 c = n
111 nb += 1
112 if c == head:
113 gdb.write("list is consistent: {} node(s)\n".format(nb))
114 return
115
116
117class LxListChk(gdb.Command):
118 """Verify a list consistency"""
119
120 def __init__(self):
121 super(LxListChk, self).__init__("lx-list-check", gdb.COMMAND_DATA,
122 gdb.COMPLETE_EXPRESSION)
123
124 def invoke(self, arg, from_tty):
125 argv = gdb.string_to_argv(arg)
126 if len(argv) != 1:
127 raise gdb.GdbError("lx-list-check takes one argument")
128 list_check(gdb.parse_and_eval(argv[0]))
129
130
131LxListChk()
diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py
new file mode 100644
index 000000000..441b23239
--- /dev/null
+++ b/scripts/gdb/linux/modules.py
@@ -0,0 +1,95 @@
1#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# module tools
5#
6# Copyright (c) Siemens AG, 2013
7#
8# Authors:
9# Jan Kiszka <jan.kiszka@siemens.com>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import gdb
15
16from linux import cpus, utils, lists
17
18
19module_type = utils.CachedType("struct module")
20
21
22def module_list():
23 global module_type
24 modules = utils.gdb_eval_or_none("modules")
25 if modules is None:
26 return
27
28 module_ptr_type = module_type.get_type().pointer()
29
30 for module in lists.list_for_each_entry(modules, module_ptr_type, "list"):
31 yield module
32
33
34def find_module_by_name(name):
35 for module in module_list():
36 if module['name'].string() == name:
37 return module
38 return None
39
40
41class LxModule(gdb.Function):
42 """Find module by name and return the module variable.
43
44$lx_module("MODULE"): Given the name MODULE, iterate over all loaded modules
45of the target and return that module variable which MODULE matches."""
46
47 def __init__(self):
48 super(LxModule, self).__init__("lx_module")
49
50 def invoke(self, mod_name):
51 mod_name = mod_name.string()
52 module = find_module_by_name(mod_name)
53 if module:
54 return module.dereference()
55 else:
56 raise gdb.GdbError("Unable to find MODULE " + mod_name)
57
58
59LxModule()
60
61
62class LxLsmod(gdb.Command):
63 """List currently loaded modules."""
64
65 _module_use_type = utils.CachedType("struct module_use")
66
67 def __init__(self):
68 super(LxLsmod, self).__init__("lx-lsmod", gdb.COMMAND_DATA)
69
70 def invoke(self, arg, from_tty):
71 gdb.write(
72 "Address{0} Module Size Used by\n".format(
73 " " if utils.get_long_type().sizeof == 8 else ""))
74
75 for module in module_list():
76 layout = module['core_layout']
77 gdb.write("{address} {name:<19} {size:>8} {ref}".format(
78 address=str(layout['base']).split()[0],
79 name=module['name'].string(),
80 size=str(layout['size']),
81 ref=str(module['refcnt']['counter'] - 1)))
82
83 t = self._module_use_type.get_type().pointer()
84 first = True
85 sources = module['source_list']
86 for use in lists.list_for_each_entry(sources, t, "source_list"):
87 gdb.write("{separator}{name}".format(
88 separator=" " if first else ",",
89 name=use['source']['name'].string()))
90 first = False
91
92 gdb.write("\n")
93
94
95LxLsmod()
diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py
new file mode 100644
index 000000000..09cd87192
--- /dev/null
+++ b/scripts/gdb/linux/proc.py
@@ -0,0 +1,275 @@
1#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# Kernel proc information reader
5#
6# Copyright (c) 2016 Linaro Ltd
7#
8# Authors:
9# Kieran Bingham <kieran.bingham@linaro.org>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import gdb
15from linux import constants
16from linux import utils
17from linux import tasks
18from linux import lists
19from struct import *
20
21
22class LxCmdLine(gdb.Command):
23 """ Report the Linux Commandline used in the current kernel.
24 Equivalent to cat /proc/cmdline on a running target"""
25
26 def __init__(self):
27 super(LxCmdLine, self).__init__("lx-cmdline", gdb.COMMAND_DATA)
28
29 def invoke(self, arg, from_tty):
30 gdb.write(gdb.parse_and_eval("saved_command_line").string() + "\n")
31
32
33LxCmdLine()
34
35
36class LxVersion(gdb.Command):
37 """ Report the Linux Version of the current kernel.
38 Equivalent to cat /proc/version on a running target"""
39
40 def __init__(self):
41 super(LxVersion, self).__init__("lx-version", gdb.COMMAND_DATA)
42
43 def invoke(self, arg, from_tty):
44 # linux_banner should contain a newline
45 gdb.write(gdb.parse_and_eval("(char *)linux_banner").string())
46
47
48LxVersion()
49
50
51# Resource Structure Printers
52# /proc/iomem
53# /proc/ioports
54
55def get_resources(resource, depth):
56 while resource:
57 yield resource, depth
58
59 child = resource['child']
60 if child:
61 for res, deep in get_resources(child, depth + 1):
62 yield res, deep
63
64 resource = resource['sibling']
65
66
67def show_lx_resources(resource_str):
68 resource = gdb.parse_and_eval(resource_str)
69 width = 4 if resource['end'] < 0x10000 else 8
70 # Iterate straight to the first child
71 for res, depth in get_resources(resource['child'], 0):
72 start = int(res['start'])
73 end = int(res['end'])
74 gdb.write(" " * depth * 2 +
75 "{0:0{1}x}-".format(start, width) +
76 "{0:0{1}x} : ".format(end, width) +
77 res['name'].string() + "\n")
78
79
80class LxIOMem(gdb.Command):
81 """Identify the IO memory resource locations defined by the kernel
82
83Equivalent to cat /proc/iomem on a running target"""
84
85 def __init__(self):
86 super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA)
87
88 def invoke(self, arg, from_tty):
89 return show_lx_resources("iomem_resource")
90
91
92LxIOMem()
93
94
95class LxIOPorts(gdb.Command):
96 """Identify the IO port resource locations defined by the kernel
97
98Equivalent to cat /proc/ioports on a running target"""
99
100 def __init__(self):
101 super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA)
102
103 def invoke(self, arg, from_tty):
104 return show_lx_resources("ioport_resource")
105
106
107LxIOPorts()
108
109
110# Mount namespace viewer
111# /proc/mounts
112
113def info_opts(lst, opt):
114 opts = ""
115 for key, string in lst.items():
116 if opt & key:
117 opts += string
118 return opts
119
120
121FS_INFO = {constants.LX_SB_SYNCHRONOUS: ",sync",
122 constants.LX_SB_MANDLOCK: ",mand",
123 constants.LX_SB_DIRSYNC: ",dirsync",
124 constants.LX_SB_NOATIME: ",noatime",
125 constants.LX_SB_NODIRATIME: ",nodiratime"}
126
127MNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid",
128 constants.LX_MNT_NODEV: ",nodev",
129 constants.LX_MNT_NOEXEC: ",noexec",
130 constants.LX_MNT_NOATIME: ",noatime",
131 constants.LX_MNT_NODIRATIME: ",nodiratime",
132 constants.LX_MNT_RELATIME: ",relatime"}
133
134mount_type = utils.CachedType("struct mount")
135mount_ptr_type = mount_type.get_type().pointer()
136
137
138class LxMounts(gdb.Command):
139 """Report the VFS mounts of the current process namespace.
140
141Equivalent to cat /proc/mounts on a running target
142An integer value can be supplied to display the mount
143values of that process namespace"""
144
145 def __init__(self):
146 super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA)
147
148 # Equivalent to proc_namespace.c:show_vfsmnt
149 # However, that has the ability to call into s_op functions
150 # whereas we cannot and must make do with the information we can obtain.
151 def invoke(self, arg, from_tty):
152 argv = gdb.string_to_argv(arg)
153 if len(argv) >= 1:
154 try:
155 pid = int(argv[0])
156 except gdb.error:
157 raise gdb.GdbError("Provide a PID as integer value")
158 else:
159 pid = 1
160
161 task = tasks.get_task_by_pid(pid)
162 if not task:
163 raise gdb.GdbError("Couldn't find a process with PID {}"
164 .format(pid))
165
166 namespace = task['nsproxy']['mnt_ns']
167 if not namespace:
168 raise gdb.GdbError("No namespace for current process")
169
170 gdb.write("{:^18} {:^15} {:>9} {} {} options\n".format(
171 "mount", "super_block", "devname", "pathname", "fstype"))
172
173 for vfs in lists.list_for_each_entry(namespace['list'],
174 mount_ptr_type, "mnt_list"):
175 devname = vfs['mnt_devname'].string()
176 devname = devname if devname else "none"
177
178 pathname = ""
179 parent = vfs
180 while True:
181 mntpoint = parent['mnt_mountpoint']
182 pathname = utils.dentry_name(mntpoint) + pathname
183 if (parent == parent['mnt_parent']):
184 break
185 parent = parent['mnt_parent']
186
187 if (pathname == ""):
188 pathname = "/"
189
190 superblock = vfs['mnt']['mnt_sb']
191 fstype = superblock['s_type']['name'].string()
192 s_flags = int(superblock['s_flags'])
193 m_flags = int(vfs['mnt']['mnt_flags'])
194 rd = "ro" if (s_flags & constants.LX_SB_RDONLY) else "rw"
195
196 gdb.write("{} {} {} {} {} {}{}{} 0 0\n".format(
197 vfs.format_string(), superblock.format_string(), devname,
198 pathname, fstype, rd, info_opts(FS_INFO, s_flags),
199 info_opts(MNT_INFO, m_flags)))
200
201
202LxMounts()
203
204
205class LxFdtDump(gdb.Command):
206 """Output Flattened Device Tree header and dump FDT blob to the filename
207 specified as the command argument. Equivalent to
208 'cat /proc/fdt > fdtdump.dtb' on a running target"""
209
210 def __init__(self):
211 super(LxFdtDump, self).__init__("lx-fdtdump", gdb.COMMAND_DATA,
212 gdb.COMPLETE_FILENAME)
213
214 def fdthdr_to_cpu(self, fdt_header):
215
216 fdt_header_be = ">IIIIIII"
217 fdt_header_le = "<IIIIIII"
218
219 if utils.get_target_endianness() == 1:
220 output_fmt = fdt_header_le
221 else:
222 output_fmt = fdt_header_be
223
224 return unpack(output_fmt, pack(fdt_header_be,
225 fdt_header['magic'],
226 fdt_header['totalsize'],
227 fdt_header['off_dt_struct'],
228 fdt_header['off_dt_strings'],
229 fdt_header['off_mem_rsvmap'],
230 fdt_header['version'],
231 fdt_header['last_comp_version']))
232
233 def invoke(self, arg, from_tty):
234
235 if not constants.LX_CONFIG_OF:
236 raise gdb.GdbError("Kernel not compiled with CONFIG_OF\n")
237
238 if len(arg) == 0:
239 filename = "fdtdump.dtb"
240 else:
241 filename = arg
242
243 py_fdt_header_ptr = gdb.parse_and_eval(
244 "(const struct fdt_header *) initial_boot_params")
245 py_fdt_header = py_fdt_header_ptr.dereference()
246
247 fdt_header = self.fdthdr_to_cpu(py_fdt_header)
248
249 if fdt_header[0] != constants.LX_OF_DT_HEADER:
250 raise gdb.GdbError("No flattened device tree magic found\n")
251
252 gdb.write("fdt_magic: 0x{:02X}\n".format(fdt_header[0]))
253 gdb.write("fdt_totalsize: 0x{:02X}\n".format(fdt_header[1]))
254 gdb.write("off_dt_struct: 0x{:02X}\n".format(fdt_header[2]))
255 gdb.write("off_dt_strings: 0x{:02X}\n".format(fdt_header[3]))
256 gdb.write("off_mem_rsvmap: 0x{:02X}\n".format(fdt_header[4]))
257 gdb.write("version: {}\n".format(fdt_header[5]))
258 gdb.write("last_comp_version: {}\n".format(fdt_header[6]))
259
260 inf = gdb.inferiors()[0]
261 fdt_buf = utils.read_memoryview(inf, py_fdt_header_ptr,
262 fdt_header[1]).tobytes()
263
264 try:
265 f = open(filename, 'wb')
266 except gdb.error:
267 raise gdb.GdbError("Could not open file to dump fdt")
268
269 f.write(fdt_buf)
270 f.close()
271
272 gdb.write("Dumped fdt blob to " + filename + "\n")
273
274
275LxFdtDump()
diff --git a/scripts/gdb/linux/rbtree.py b/scripts/gdb/linux/rbtree.py
new file mode 100644
index 000000000..fe462855e
--- /dev/null
+++ b/scripts/gdb/linux/rbtree.py
@@ -0,0 +1,177 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Copyright 2019 Google LLC.
4
5import gdb
6
7from linux import utils
8
9rb_root_type = utils.CachedType("struct rb_root")
10rb_node_type = utils.CachedType("struct rb_node")
11
12
13def rb_first(root):
14 if root.type == rb_root_type.get_type():
15 node = root.address.cast(rb_root_type.get_type().pointer())
16 elif root.type != rb_root_type.get_type().pointer():
17 raise gdb.GdbError("Must be struct rb_root not {}".format(root.type))
18
19 node = root['rb_node']
20 if node == 0:
21 return None
22
23 while node['rb_left']:
24 node = node['rb_left']
25
26 return node
27
28
29def rb_last(root):
30 if root.type == rb_root_type.get_type():
31 node = root.address.cast(rb_root_type.get_type().pointer())
32 elif root.type != rb_root_type.get_type().pointer():
33 raise gdb.GdbError("Must be struct rb_root not {}".format(root.type))
34
35 node = root['rb_node']
36 if node == 0:
37 return None
38
39 while node['rb_right']:
40 node = node['rb_right']
41
42 return node
43
44
45def rb_parent(node):
46 parent = gdb.Value(node['__rb_parent_color'] & ~3)
47 return parent.cast(rb_node_type.get_type().pointer())
48
49
50def rb_empty_node(node):
51 return node['__rb_parent_color'] == node.address
52
53
54def rb_next(node):
55 if node.type == rb_node_type.get_type():
56 node = node.address.cast(rb_node_type.get_type().pointer())
57 elif node.type != rb_node_type.get_type().pointer():
58 raise gdb.GdbError("Must be struct rb_node not {}".format(node.type))
59
60 if rb_empty_node(node):
61 return None
62
63 if node['rb_right']:
64 node = node['rb_right']
65 while node['rb_left']:
66 node = node['rb_left']
67 return node
68
69 parent = rb_parent(node)
70 while parent and node == parent['rb_right']:
71 node = parent
72 parent = rb_parent(node)
73
74 return parent
75
76
77def rb_prev(node):
78 if node.type == rb_node_type.get_type():
79 node = node.address.cast(rb_node_type.get_type().pointer())
80 elif node.type != rb_node_type.get_type().pointer():
81 raise gdb.GdbError("Must be struct rb_node not {}".format(node.type))
82
83 if rb_empty_node(node):
84 return None
85
86 if node['rb_left']:
87 node = node['rb_left']
88 while node['rb_right']:
89 node = node['rb_right']
90 return node.dereference()
91
92 parent = rb_parent(node)
93 while parent and node == parent['rb_left'].dereference():
94 node = parent
95 parent = rb_parent(node)
96
97 return parent
98
99
100class LxRbFirst(gdb.Function):
101 """Lookup and return a node from an RBTree
102
103$lx_rb_first(root): Return the node at the given index.
104If index is omitted, the root node is dereferenced and returned."""
105
106 def __init__(self):
107 super(LxRbFirst, self).__init__("lx_rb_first")
108
109 def invoke(self, root):
110 result = rb_first(root)
111 if result is None:
112 raise gdb.GdbError("No entry in tree")
113
114 return result
115
116
117LxRbFirst()
118
119
120class LxRbLast(gdb.Function):
121 """Lookup and return a node from an RBTree.
122
123$lx_rb_last(root): Return the node at the given index.
124If index is omitted, the root node is dereferenced and returned."""
125
126 def __init__(self):
127 super(LxRbLast, self).__init__("lx_rb_last")
128
129 def invoke(self, root):
130 result = rb_last(root)
131 if result is None:
132 raise gdb.GdbError("No entry in tree")
133
134 return result
135
136
137LxRbLast()
138
139
140class LxRbNext(gdb.Function):
141 """Lookup and return a node from an RBTree.
142
143$lx_rb_next(node): Return the node at the given index.
144If index is omitted, the root node is dereferenced and returned."""
145
146 def __init__(self):
147 super(LxRbNext, self).__init__("lx_rb_next")
148
149 def invoke(self, node):
150 result = rb_next(node)
151 if result is None:
152 raise gdb.GdbError("No entry in tree")
153
154 return result
155
156
157LxRbNext()
158
159
160class LxRbPrev(gdb.Function):
161 """Lookup and return a node from an RBTree.
162
163$lx_rb_prev(node): Return the node at the given index.
164If index is omitted, the root node is dereferenced and returned."""
165
166 def __init__(self):
167 super(LxRbPrev, self).__init__("lx_rb_prev")
168
169 def invoke(self, node):
170 result = rb_prev(node)
171 if result is None:
172 raise gdb.GdbError("No entry in tree")
173
174 return result
175
176
177LxRbPrev()
diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py
new file mode 100644
index 000000000..1be9763cf
--- /dev/null
+++ b/scripts/gdb/linux/symbols.py
@@ -0,0 +1,187 @@
1#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# load kernel and module symbols
5#
6# Copyright (c) Siemens AG, 2011-2013
7#
8# Authors:
9# Jan Kiszka <jan.kiszka@siemens.com>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import gdb
15import os
16import re
17
18from linux import modules, utils
19
20
21if hasattr(gdb, 'Breakpoint'):
22 class LoadModuleBreakpoint(gdb.Breakpoint):
23 def __init__(self, spec, gdb_command):
24 super(LoadModuleBreakpoint, self).__init__(spec, internal=True)
25 self.silent = True
26 self.gdb_command = gdb_command
27
28 def stop(self):
29 module = gdb.parse_and_eval("mod")
30 module_name = module['name'].string()
31 cmd = self.gdb_command
32
33 # enforce update if object file is not found
34 cmd.module_files_updated = False
35
36 # Disable pagination while reporting symbol (re-)loading.
37 # The console input is blocked in this context so that we would
38 # get stuck waiting for the user to acknowledge paged output.
39 show_pagination = gdb.execute("show pagination", to_string=True)
40 pagination = show_pagination.endswith("on.\n")
41 gdb.execute("set pagination off")
42
43 if module_name in cmd.loaded_modules:
44 gdb.write("refreshing all symbols to reload module "
45 "'{0}'\n".format(module_name))
46 cmd.load_all_symbols()
47 else:
48 cmd.load_module_symbols(module)
49
50 # restore pagination state
51 gdb.execute("set pagination %s" % ("on" if pagination else "off"))
52
53 return False
54
55
56class LxSymbols(gdb.Command):
57 """(Re-)load symbols of Linux kernel and currently loaded modules.
58
59The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
60are scanned recursively, starting in the same directory. Optionally, the module
61search path can be extended by a space separated list of paths passed to the
62lx-symbols command."""
63
64 module_paths = []
65 module_files = []
66 module_files_updated = False
67 loaded_modules = []
68 breakpoint = None
69
70 def __init__(self):
71 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
72 gdb.COMPLETE_FILENAME)
73
74 def _update_module_files(self):
75 self.module_files = []
76 for path in self.module_paths:
77 gdb.write("scanning for modules in {0}\n".format(path))
78 for root, dirs, files in os.walk(path):
79 for name in files:
80 if name.endswith(".ko") or name.endswith(".ko.debug"):
81 self.module_files.append(root + "/" + name)
82 self.module_files_updated = True
83
84 def _get_module_file(self, module_name):
85 module_pattern = ".*/{0}\.ko(?:.debug)?$".format(
86 module_name.replace("_", r"[_\-]"))
87 for name in self.module_files:
88 if re.match(module_pattern, name) and os.path.exists(name):
89 return name
90 return None
91
92 def _section_arguments(self, module):
93 try:
94 sect_attrs = module['sect_attrs'].dereference()
95 except gdb.error:
96 return ""
97 attrs = sect_attrs['attrs']
98 section_name_to_address = {
99 attrs[n]['battr']['attr']['name'].string(): attrs[n]['address']
100 for n in range(int(sect_attrs['nsections']))}
101 args = []
102 for section_name in [".data", ".data..read_mostly", ".rodata", ".bss",
103 ".text", ".text.hot", ".text.unlikely"]:
104 address = section_name_to_address.get(section_name)
105 if address:
106 args.append(" -s {name} {addr}".format(
107 name=section_name, addr=str(address)))
108 return "".join(args)
109
110 def load_module_symbols(self, module):
111 module_name = module['name'].string()
112 module_addr = str(module['core_layout']['base']).split()[0]
113
114 module_file = self._get_module_file(module_name)
115 if not module_file and not self.module_files_updated:
116 self._update_module_files()
117 module_file = self._get_module_file(module_name)
118
119 if module_file:
120 if utils.is_target_arch('s390'):
121 # Module text is preceded by PLT stubs on s390.
122 module_arch = module['arch']
123 plt_offset = int(module_arch['plt_offset'])
124 plt_size = int(module_arch['plt_size'])
125 module_addr = hex(int(module_addr, 0) + plt_offset + plt_size)
126 gdb.write("loading @{addr}: {filename}\n".format(
127 addr=module_addr, filename=module_file))
128 cmdline = "add-symbol-file {filename} {addr}{sections}".format(
129 filename=module_file,
130 addr=module_addr,
131 sections=self._section_arguments(module))
132 gdb.execute(cmdline, to_string=True)
133 if module_name not in self.loaded_modules:
134 self.loaded_modules.append(module_name)
135 else:
136 gdb.write("no module object found for '{0}'\n".format(module_name))
137
138 def load_all_symbols(self):
139 gdb.write("loading vmlinux\n")
140
141 # Dropping symbols will disable all breakpoints. So save their states
142 # and restore them afterward.
143 saved_states = []
144 if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
145 for bp in gdb.breakpoints():
146 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
147
148 # drop all current symbols and reload vmlinux
149 orig_vmlinux = 'vmlinux'
150 for obj in gdb.objfiles():
151 if obj.filename.endswith('vmlinux'):
152 orig_vmlinux = obj.filename
153 gdb.execute("symbol-file", to_string=True)
154 gdb.execute("symbol-file {0}".format(orig_vmlinux))
155
156 self.loaded_modules = []
157 module_list = modules.module_list()
158 if not module_list:
159 gdb.write("no modules found\n")
160 else:
161 [self.load_module_symbols(module) for module in module_list]
162
163 for saved_state in saved_states:
164 saved_state['breakpoint'].enabled = saved_state['enabled']
165
166 def invoke(self, arg, from_tty):
167 self.module_paths = [os.path.expanduser(p) for p in arg.split()]
168 self.module_paths.append(os.getcwd())
169
170 # enforce update
171 self.module_files = []
172 self.module_files_updated = False
173
174 self.load_all_symbols()
175
176 if hasattr(gdb, 'Breakpoint'):
177 if self.breakpoint is not None:
178 self.breakpoint.delete()
179 self.breakpoint = None
180 self.breakpoint = LoadModuleBreakpoint(
181 "kernel/module.c:do_init_module", self)
182 else:
183 gdb.write("Note: symbol update on module loading not supported "
184 "with this gdb version\n")
185
186
187LxSymbols()
diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py
new file mode 100644
index 000000000..17ec19e9b
--- /dev/null
+++ b/scripts/gdb/linux/tasks.py
@@ -0,0 +1,140 @@
1#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# task & thread tools
5#
6# Copyright (c) Siemens AG, 2011-2013
7#
8# Authors:
9# Jan Kiszka <jan.kiszka@siemens.com>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import gdb
15
16from linux import utils
17
18
19task_type = utils.CachedType("struct task_struct")
20
21
22def task_lists():
23 task_ptr_type = task_type.get_type().pointer()
24 init_task = gdb.parse_and_eval("init_task").address
25 t = g = init_task
26
27 while True:
28 while True:
29 yield t
30
31 t = utils.container_of(t['thread_group']['next'],
32 task_ptr_type, "thread_group")
33 if t == g:
34 break
35
36 t = g = utils.container_of(g['tasks']['next'],
37 task_ptr_type, "tasks")
38 if t == init_task:
39 return
40
41
42def get_task_by_pid(pid):
43 for task in task_lists():
44 if int(task['pid']) == pid:
45 return task
46 return None
47
48
49class LxTaskByPidFunc(gdb.Function):
50 """Find Linux task by PID and return the task_struct variable.
51
52$lx_task_by_pid(PID): Given PID, iterate over all tasks of the target and
53return that task_struct variable which PID matches."""
54
55 def __init__(self):
56 super(LxTaskByPidFunc, self).__init__("lx_task_by_pid")
57
58 def invoke(self, pid):
59 task = get_task_by_pid(pid)
60 if task:
61 return task.dereference()
62 else:
63 raise gdb.GdbError("No task of PID " + str(pid))
64
65
66LxTaskByPidFunc()
67
68
69class LxPs(gdb.Command):
70 """Dump Linux tasks."""
71
72 def __init__(self):
73 super(LxPs, self).__init__("lx-ps", gdb.COMMAND_DATA)
74
75 def invoke(self, arg, from_tty):
76 gdb.write("{:>10} {:>12} {:>7}\n".format("TASK", "PID", "COMM"))
77 for task in task_lists():
78 gdb.write("{} {:^5} {}\n".format(
79 task.format_string().split()[0],
80 task["pid"].format_string(),
81 task["comm"].string()))
82
83
84LxPs()
85
86
87thread_info_type = utils.CachedType("struct thread_info")
88
89ia64_task_size = None
90
91
92def get_thread_info(task):
93 thread_info_ptr_type = thread_info_type.get_type().pointer()
94 if utils.is_target_arch("ia64"):
95 global ia64_task_size
96 if ia64_task_size is None:
97 ia64_task_size = gdb.parse_and_eval("sizeof(struct task_struct)")
98 thread_info_addr = task.address + ia64_task_size
99 thread_info = thread_info_addr.cast(thread_info_ptr_type)
100 else:
101 if task.type.fields()[0].type == thread_info_type.get_type():
102 return task['thread_info']
103 thread_info = task['stack'].cast(thread_info_ptr_type)
104 return thread_info.dereference()
105
106
107class LxThreadInfoFunc (gdb.Function):
108 """Calculate Linux thread_info from task variable.
109
110$lx_thread_info(TASK): Given TASK, return the corresponding thread_info
111variable."""
112
113 def __init__(self):
114 super(LxThreadInfoFunc, self).__init__("lx_thread_info")
115
116 def invoke(self, task):
117 return get_thread_info(task)
118
119
120LxThreadInfoFunc()
121
122
123class LxThreadInfoByPidFunc (gdb.Function):
124 """Calculate Linux thread_info from task variable found by pid
125
126$lx_thread_info_by_pid(PID): Given PID, return the corresponding thread_info
127variable."""
128
129 def __init__(self):
130 super(LxThreadInfoByPidFunc, self).__init__("lx_thread_info_by_pid")
131
132 def invoke(self, pid):
133 task = get_task_by_pid(pid)
134 if task:
135 return get_thread_info(task.dereference())
136 else:
137 raise gdb.GdbError("No task of PID " + str(pid))
138
139
140LxThreadInfoByPidFunc()
diff --git a/scripts/gdb/linux/timerlist.py b/scripts/gdb/linux/timerlist.py
new file mode 100644
index 000000000..071d0dd5a
--- /dev/null
+++ b/scripts/gdb/linux/timerlist.py
@@ -0,0 +1,219 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Copyright 2019 Google LLC.
4
5import binascii
6import gdb
7
8from linux import constants
9from linux import cpus
10from linux import rbtree
11from linux import utils
12
13timerqueue_node_type = utils.CachedType("struct timerqueue_node").get_type()
14hrtimer_type = utils.CachedType("struct hrtimer").get_type()
15
16
17def ktime_get():
18 """Returns the current time, but not very accurately
19
20 We can't read the hardware timer itself to add any nanoseconds
21 that need to be added since we last stored the time in the
22 timekeeper. But this is probably good enough for debug purposes."""
23 tk_core = gdb.parse_and_eval("&tk_core")
24
25 return tk_core['timekeeper']['tkr_mono']['base']
26
27
28def print_timer(rb_node, idx):
29 timerqueue = utils.container_of(rb_node, timerqueue_node_type.pointer(),
30 "node")
31 timer = utils.container_of(timerqueue, hrtimer_type.pointer(), "node")
32
33 function = str(timer['function']).split(" ")[1].strip("<>")
34 softexpires = timer['_softexpires']
35 expires = timer['node']['expires']
36 now = ktime_get()
37
38 text = " #{}: <{}>, {}, ".format(idx, timer, function)
39 text += "S:{:02x}\n".format(int(timer['state']))
40 text += " # expires at {}-{} nsecs [in {} to {} nsecs]\n".format(
41 softexpires, expires, softexpires - now, expires - now)
42 return text
43
44
45def print_active_timers(base):
46 curr = base['active']['next']['node']
47 curr = curr.address.cast(rbtree.rb_node_type.get_type().pointer())
48 idx = 0
49 while curr:
50 yield print_timer(curr, idx)
51 curr = rbtree.rb_next(curr)
52 idx += 1
53
54
55def print_base(base):
56 text = " .base: {}\n".format(base.address)
57 text += " .index: {}\n".format(base['index'])
58
59 text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution)
60
61 text += " .get_time: {}\n".format(base['get_time'])
62 if constants.LX_CONFIG_HIGH_RES_TIMERS:
63 text += " .offset: {} nsecs\n".format(base['offset'])
64 text += "active timers:\n"
65 text += "".join([x for x in print_active_timers(base)])
66 return text
67
68
69def print_cpu(hrtimer_bases, cpu, max_clock_bases):
70 cpu_base = cpus.per_cpu(hrtimer_bases, cpu)
71 jiffies = gdb.parse_and_eval("jiffies_64")
72 tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched")
73 ts = cpus.per_cpu(tick_sched_ptr, cpu)
74
75 text = "cpu: {}\n".format(cpu)
76 for i in xrange(max_clock_bases):
77 text += " clock {}:\n".format(i)
78 text += print_base(cpu_base['clock_base'][i])
79
80 if constants.LX_CONFIG_HIGH_RES_TIMERS:
81 fmts = [(" .{} : {} nsecs", 'expires_next'),
82 (" .{} : {}", 'hres_active'),
83 (" .{} : {}", 'nr_events'),
84 (" .{} : {}", 'nr_retries'),
85 (" .{} : {}", 'nr_hangs'),
86 (" .{} : {}", 'max_hang_time')]
87 text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts])
88 text += "\n"
89
90 if constants.LX_CONFIG_TICK_ONESHOT:
91 fmts = [(" .{} : {}", 'nohz_mode'),
92 (" .{} : {} nsecs", 'last_tick'),
93 (" .{} : {}", 'tick_stopped'),
94 (" .{} : {}", 'idle_jiffies'),
95 (" .{} : {}", 'idle_calls'),
96 (" .{} : {}", 'idle_sleeps'),
97 (" .{} : {} nsecs", 'idle_entrytime'),
98 (" .{} : {} nsecs", 'idle_waketime'),
99 (" .{} : {} nsecs", 'idle_exittime'),
100 (" .{} : {} nsecs", 'idle_sleeptime'),
101 (" .{}: {} nsecs", 'iowait_sleeptime'),
102 (" .{} : {}", 'last_jiffies'),
103 (" .{} : {}", 'next_timer'),
104 (" .{} : {} nsecs", 'idle_expires')]
105 text += "\n".join([s.format(f, ts[f]) for s, f in fmts])
106 text += "\njiffies: {}\n".format(jiffies)
107
108 text += "\n"
109
110 return text
111
112
113def print_tickdevice(td, cpu):
114 dev = td['evtdev']
115 text = "Tick Device: mode: {}\n".format(td['mode'])
116 if cpu < 0:
117 text += "Broadcast device\n"
118 else:
119 text += "Per CPU device: {}\n".format(cpu)
120
121 text += "Clock Event Device: "
122 if dev == 0:
123 text += "<NULL>\n"
124 return text
125
126 text += "{}\n".format(dev['name'])
127 text += " max_delta_ns: {}\n".format(dev['max_delta_ns'])
128 text += " min_delta_ns: {}\n".format(dev['min_delta_ns'])
129 text += " mult: {}\n".format(dev['mult'])
130 text += " shift: {}\n".format(dev['shift'])
131 text += " mode: {}\n".format(dev['state_use_accessors'])
132 text += " next_event: {} nsecs\n".format(dev['next_event'])
133
134 text += " set_next_event: {}\n".format(dev['set_next_event'])
135
136 members = [('set_state_shutdown', " shutdown: {}\n"),
137 ('set_state_periodic', " periodic: {}\n"),
138 ('set_state_oneshot', " oneshot: {}\n"),
139 ('set_state_oneshot_stopped', " oneshot stopped: {}\n"),
140 ('tick_resume', " resume: {}\n")]
141 for member, fmt in members:
142 if dev[member]:
143 text += fmt.format(dev[member])
144
145 text += " event_handler: {}\n".format(dev['event_handler'])
146 text += " retries: {}\n".format(dev['retries'])
147
148 return text
149
150
151def pr_cpumask(mask):
152 nr_cpu_ids = 1
153 if constants.LX_NR_CPUS > 1:
154 nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids")
155
156 inf = gdb.inferiors()[0]
157 bits = mask['bits']
158 num_bytes = (nr_cpu_ids + 7) / 8
159 buf = utils.read_memoryview(inf, bits, num_bytes).tobytes()
160 buf = binascii.b2a_hex(buf)
161
162 chunks = []
163 i = num_bytes
164 while i > 0:
165 i -= 1
166 start = i * 2
167 end = start + 2
168 chunks.append(buf[start:end])
169 if i != 0 and i % 4 == 0:
170 chunks.append(',')
171
172 extra = nr_cpu_ids % 8
173 if 0 < extra <= 4:
174 chunks[0] = chunks[0][0] # Cut off the first 0
175
176 return "".join(chunks)
177
178
179class LxTimerList(gdb.Command):
180 """Print /proc/timer_list"""
181
182 def __init__(self):
183 super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA)
184
185 def invoke(self, arg, from_tty):
186 hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases")
187 max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES")
188
189 text = "Timer List Version: gdb scripts\n"
190 text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases)
191 text += "now at {} nsecs\n".format(ktime_get())
192
193 for cpu in cpus.each_online_cpu():
194 text += print_cpu(hrtimer_bases, cpu, max_clock_bases)
195
196 if constants.LX_CONFIG_GENERIC_CLOCKEVENTS:
197 if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST:
198 bc_dev = gdb.parse_and_eval("&tick_broadcast_device")
199 text += print_tickdevice(bc_dev, -1)
200 text += "\n"
201 mask = gdb.parse_and_eval("tick_broadcast_mask")
202 mask = pr_cpumask(mask)
203 text += "tick_broadcast_mask: {}\n".format(mask)
204 if constants.LX_CONFIG_TICK_ONESHOT:
205 mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask")
206 mask = pr_cpumask(mask)
207 text += "tick_broadcast_oneshot_mask: {}\n".format(mask)
208 text += "\n"
209
210 tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device")
211 for cpu in cpus.each_online_cpu():
212 tick_dev = cpus.per_cpu(tick_cpu_devices, cpu)
213 text += print_tickdevice(tick_dev, cpu)
214 text += "\n"
215
216 gdb.write(text)
217
218
219LxTimerList()
diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py
new file mode 100644
index 000000000..ff7c1799d
--- /dev/null
+++ b/scripts/gdb/linux/utils.py
@@ -0,0 +1,193 @@
1#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# common utilities
5#
6# Copyright (c) Siemens AG, 2011-2013
7#
8# Authors:
9# Jan Kiszka <jan.kiszka@siemens.com>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import gdb
15
16
17class CachedType:
18 def __init__(self, name):
19 self._type = None
20 self._name = name
21
22 def _new_objfile_handler(self, event):
23 self._type = None
24 gdb.events.new_objfile.disconnect(self._new_objfile_handler)
25
26 def get_type(self):
27 if self._type is None:
28 self._type = gdb.lookup_type(self._name)
29 if self._type is None:
30 raise gdb.GdbError(
31 "cannot resolve type '{0}'".format(self._name))
32 if hasattr(gdb, 'events') and hasattr(gdb.events, 'new_objfile'):
33 gdb.events.new_objfile.connect(self._new_objfile_handler)
34 return self._type
35
36
37long_type = CachedType("long")
38
39
40def get_long_type():
41 global long_type
42 return long_type.get_type()
43
44
45def offset_of(typeobj, field):
46 element = gdb.Value(0).cast(typeobj)
47 return int(str(element[field].address).split()[0], 16)
48
49
50def container_of(ptr, typeobj, member):
51 return (ptr.cast(get_long_type()) -
52 offset_of(typeobj, member)).cast(typeobj)
53
54
55class ContainerOf(gdb.Function):
56 """Return pointer to containing data structure.
57
58$container_of(PTR, "TYPE", "ELEMENT"): Given PTR, return a pointer to the
59data structure of the type TYPE in which PTR is the address of ELEMENT.
60Note that TYPE and ELEMENT have to be quoted as strings."""
61
62 def __init__(self):
63 super(ContainerOf, self).__init__("container_of")
64
65 def invoke(self, ptr, typename, elementname):
66 return container_of(ptr, gdb.lookup_type(typename.string()).pointer(),
67 elementname.string())
68
69
70ContainerOf()
71
72
73BIG_ENDIAN = 0
74LITTLE_ENDIAN = 1
75target_endianness = None
76
77
78def get_target_endianness():
79 global target_endianness
80 if target_endianness is None:
81 endian = gdb.execute("show endian", to_string=True)
82 if "little endian" in endian:
83 target_endianness = LITTLE_ENDIAN
84 elif "big endian" in endian:
85 target_endianness = BIG_ENDIAN
86 else:
87 raise gdb.GdbError("unknown endianness '{0}'".format(str(endian)))
88 return target_endianness
89
90
91def read_memoryview(inf, start, length):
92 return memoryview(inf.read_memory(start, length))
93
94
95def read_u16(buffer, offset):
96 buffer_val = buffer[offset:offset + 2]
97 value = [0, 0]
98
99 if type(buffer_val[0]) is str:
100 value[0] = ord(buffer_val[0])
101 value[1] = ord(buffer_val[1])
102 else:
103 value[0] = buffer_val[0]
104 value[1] = buffer_val[1]
105
106 if get_target_endianness() == LITTLE_ENDIAN:
107 return value[0] + (value[1] << 8)
108 else:
109 return value[1] + (value[0] << 8)
110
111
112def read_u32(buffer, offset):
113 if get_target_endianness() == LITTLE_ENDIAN:
114 return read_u16(buffer, offset) + (read_u16(buffer, offset + 2) << 16)
115 else:
116 return read_u16(buffer, offset + 2) + (read_u16(buffer, offset) << 16)
117
118
119def read_u64(buffer, offset):
120 if get_target_endianness() == LITTLE_ENDIAN:
121 return read_u32(buffer, offset) + (read_u32(buffer, offset + 4) << 32)
122 else:
123 return read_u32(buffer, offset + 4) + (read_u32(buffer, offset) << 32)
124
125
126def read_ulong(buffer, offset):
127 if get_long_type().sizeof == 8:
128 return read_u64(buffer, offset)
129 else:
130 return read_u32(buffer, offset)
131
132
133target_arch = None
134
135
136def is_target_arch(arch):
137 if hasattr(gdb.Frame, 'architecture'):
138 return arch in gdb.newest_frame().architecture().name()
139 else:
140 global target_arch
141 if target_arch is None:
142 target_arch = gdb.execute("show architecture", to_string=True)
143 return arch in target_arch
144
145
146GDBSERVER_QEMU = 0
147GDBSERVER_KGDB = 1
148gdbserver_type = None
149
150
151def get_gdbserver_type():
152 def exit_handler(event):
153 global gdbserver_type
154 gdbserver_type = None
155 gdb.events.exited.disconnect(exit_handler)
156
157 def probe_qemu():
158 try:
159 return gdb.execute("monitor info version", to_string=True) != ""
160 except gdb.error:
161 return False
162
163 def probe_kgdb():
164 try:
165 thread_info = gdb.execute("info thread 2", to_string=True)
166 return "shadowCPU0" in thread_info
167 except gdb.error:
168 return False
169
170 global gdbserver_type
171 if gdbserver_type is None:
172 if probe_qemu():
173 gdbserver_type = GDBSERVER_QEMU
174 elif probe_kgdb():
175 gdbserver_type = GDBSERVER_KGDB
176 if gdbserver_type is not None and hasattr(gdb, 'events'):
177 gdb.events.exited.connect(exit_handler)
178 return gdbserver_type
179
180
181def gdb_eval_or_none(expresssion):
182 try:
183 return gdb.parse_and_eval(expresssion)
184 except gdb.error:
185 return None
186
187
188def dentry_name(d):
189 parent = d['d_parent']
190 if parent == d or parent == 0:
191 return ""
192 p = dentry_name(d['d_parent']) + "/"
193 return p + d['d_iname'].string()
diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py
new file mode 100644
index 000000000..4136dc2c5
--- /dev/null
+++ b/scripts/gdb/vmlinux-gdb.py
@@ -0,0 +1,39 @@
1#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# loader module
5#
6# Copyright (c) Siemens AG, 2012, 2013
7#
8# Authors:
9# Jan Kiszka <jan.kiszka@siemens.com>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import os
15
16sys.path.insert(0, os.path.dirname(__file__) + "/scripts/gdb")
17
18try:
19 gdb.parse_and_eval("0")
20 gdb.execute("", to_string=True)
21except:
22 gdb.write("NOTE: gdb 7.2 or later required for Linux helper scripts to "
23 "work.\n")
24else:
25 import linux.utils
26 import linux.symbols
27 import linux.modules
28 import linux.dmesg
29 import linux.tasks
30 import linux.config
31 import linux.cpus
32 import linux.lists
33 import linux.rbtree
34 import linux.proc
35 import linux.constants
36 import linux.timerlist
37 import linux.clk
38 import linux.genpd
39 import linux.device