diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2016-06-07 12:04:56 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2016-06-07 12:04:56 -0400 |
commit | c853f18b640f3e58ba14ffb25e551be8af218209 (patch) | |
tree | 89adc65667f124c21f2104422fcaed991da450ab /scripts/gdb | |
parent | aff093d4bbca91f543e24cde2135f393b8130f4b (diff) | |
parent | af8c34ce6ae32addda3788d54a7e340cad22516b (diff) |
Merge tag 'v4.7-rc2' into v4l_for_linus
Linux 4.7-rc2
* tag 'v4.7-rc2': (10914 commits)
Linux 4.7-rc2
devpts: Make each mount of devpts an independent filesystem.
parisc: Move die_if_kernel() prototype into traps.h header
parisc: Fix pagefault crash in unaligned __get_user() call
parisc: Fix printk time during boot
parisc: Fix backtrace on PA-RISC
mm, page_alloc: recalculate the preferred zoneref if the context can ignore memory policies
mm, page_alloc: reset zonelist iterator after resetting fair zone allocation policy
mm, oom_reaper: do not use siglock in try_oom_reaper()
mm, page_alloc: prevent infinite loop in buffered_rmqueue()
checkpatch: reduce git commit description style false positives
mm/z3fold.c: avoid modifying HEADLESS page and minor cleanup
memcg: add RCU locking around css_for_each_descendant_pre() in memcg_offline_kmem()
mm: check the return value of lookup_page_ext for all call sites
kdump: fix dmesg gdbmacro to work with record based printk
mm: fix overflow in vm_map_ram()
Btrfs: deal with duplciates during extent_map insertion in btrfs_get_extent
arm64: fix alignment when RANDOMIZE_TEXT_OFFSET is enabled
arm64: move {PAGE,CONT}_SHIFT into Kconfig
arm64: mm: dump: log span level
...
Diffstat (limited to 'scripts/gdb')
-rw-r--r-- | scripts/gdb/linux/Makefile | 12 | ||||
-rw-r--r-- | scripts/gdb/linux/constants.py.in | 59 | ||||
-rw-r--r-- | scripts/gdb/linux/cpus.py | 38 | ||||
-rw-r--r-- | scripts/gdb/linux/dmesg.py | 11 | ||||
-rw-r--r-- | scripts/gdb/linux/lists.py | 21 | ||||
-rw-r--r-- | scripts/gdb/linux/modules.py | 24 | ||||
-rw-r--r-- | scripts/gdb/linux/proc.py | 156 | ||||
-rw-r--r-- | scripts/gdb/linux/radixtree.py | 97 | ||||
-rw-r--r-- | scripts/gdb/linux/tasks.py | 19 | ||||
-rw-r--r-- | scripts/gdb/linux/utils.py | 32 | ||||
-rw-r--r-- | scripts/gdb/vmlinux-gdb.py | 2 |
11 files changed, 450 insertions, 21 deletions
diff --git a/scripts/gdb/linux/Makefile b/scripts/gdb/linux/Makefile index 6cf1ecf61057..cd129e65d1ff 100644 --- a/scripts/gdb/linux/Makefile +++ b/scripts/gdb/linux/Makefile | |||
@@ -8,4 +8,14 @@ ifneq ($(KBUILD_SRC),) | |||
8 | endif | 8 | endif |
9 | @: | 9 | @: |
10 | 10 | ||
11 | clean-files := *.pyc *.pyo $(if $(KBUILD_SRC),*.py) | 11 | quiet_cmd_gen_constants_py = GEN $@ |
12 | cmd_gen_constants_py = \ | ||
13 | $(CPP) -E -x c -P $(c_flags) $< > $@ ;\ | ||
14 | sed -i '1,/<!-- end-c-headers -->/d;' $@ | ||
15 | |||
16 | $(obj)/constants.py: $(SRCTREE)/$(obj)/constants.py.in | ||
17 | $(call if_changed,gen_constants_py) | ||
18 | |||
19 | build_constants_py: $(obj)/constants.py | ||
20 | |||
21 | clean-files := *.pyc *.pyo $(if $(KBUILD_SRC),*.py) $(obj)/constants.py | ||
diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in new file mode 100644 index 000000000000..07e6c2befe36 --- /dev/null +++ b/scripts/gdb/linux/constants.py.in | |||
@@ -0,0 +1,59 @@ | |||
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/fs.h> | ||
16 | #include <linux/mount.h> | ||
17 | #include <linux/radix-tree.h> | ||
18 | |||
19 | /* We need to stringify expanded macros so that they can be parsed */ | ||
20 | |||
21 | #define STRING(x) #x | ||
22 | #define XSTRING(x) STRING(x) | ||
23 | |||
24 | #define LX_VALUE(x) LX_##x = x | ||
25 | #define LX_GDBPARSED(x) LX_##x = gdb.parse_and_eval(XSTRING(x)) | ||
26 | |||
27 | /* | ||
28 | * IS_ENABLED generates (a || b) which is not compatible with python | ||
29 | * We can only switch on configuration items we know are available | ||
30 | * Therefore - IS_BUILTIN() is more appropriate | ||
31 | */ | ||
32 | #define LX_CONFIG(x) LX_##x = IS_BUILTIN(x) | ||
33 | |||
34 | /* The build system will take care of deleting everything above this marker */ | ||
35 | <!-- end-c-headers --> | ||
36 | |||
37 | import gdb | ||
38 | |||
39 | /* linux/fs.h */ | ||
40 | LX_VALUE(MS_RDONLY) | ||
41 | LX_VALUE(MS_SYNCHRONOUS) | ||
42 | LX_VALUE(MS_MANDLOCK) | ||
43 | LX_VALUE(MS_DIRSYNC) | ||
44 | LX_VALUE(MS_NOATIME) | ||
45 | LX_VALUE(MS_NODIRATIME) | ||
46 | |||
47 | /* linux/mount.h */ | ||
48 | LX_VALUE(MNT_NOSUID) | ||
49 | LX_VALUE(MNT_NODEV) | ||
50 | LX_VALUE(MNT_NOEXEC) | ||
51 | LX_VALUE(MNT_NOATIME) | ||
52 | LX_VALUE(MNT_NODIRATIME) | ||
53 | LX_VALUE(MNT_RELATIME) | ||
54 | |||
55 | /* linux/radix-tree.h */ | ||
56 | LX_VALUE(RADIX_TREE_INDIRECT_PTR) | ||
57 | LX_GDBPARSED(RADIX_TREE_HEIGHT_MASK) | ||
58 | LX_GDBPARSED(RADIX_TREE_MAP_SHIFT) | ||
59 | LX_GDBPARSED(RADIX_TREE_MAP_MASK) | ||
diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py index 4297b83fedef..ca11e8df31b6 100644 --- a/scripts/gdb/linux/cpus.py +++ b/scripts/gdb/linux/cpus.py | |||
@@ -97,9 +97,47 @@ def cpu_list(mask_name): | |||
97 | bits >>= 1 | 97 | bits >>= 1 |
98 | bit += 1 | 98 | bit += 1 |
99 | 99 | ||
100 | yield int(cpu) | ||
101 | |||
102 | |||
103 | def each_online_cpu(): | ||
104 | for cpu in cpu_list("__cpu_online_mask"): | ||
105 | yield cpu | ||
106 | |||
107 | |||
108 | def each_present_cpu(): | ||
109 | for cpu in cpu_list("__cpu_present_mask"): | ||
110 | yield cpu | ||
111 | |||
112 | |||
113 | def each_possible_cpu(): | ||
114 | for cpu in cpu_list("__cpu_possible_mask"): | ||
115 | yield cpu | ||
116 | |||
117 | |||
118 | def each_active_cpu(): | ||
119 | for cpu in cpu_list("__cpu_active_mask"): | ||
100 | yield cpu | 120 | yield cpu |
101 | 121 | ||
102 | 122 | ||
123 | class LxCpus(gdb.Command): | ||
124 | """List CPU status arrays | ||
125 | |||
126 | Displays the known state of each CPU based on the kernel masks | ||
127 | and 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 | LxCpus() | ||
139 | |||
140 | |||
103 | class PerCpu(gdb.Function): | 141 | class PerCpu(gdb.Function): |
104 | """Return per-cpu variable. | 142 | """Return per-cpu variable. |
105 | 143 | ||
diff --git a/scripts/gdb/linux/dmesg.py b/scripts/gdb/linux/dmesg.py index 927d0d2a3145..f9b92ece7834 100644 --- a/scripts/gdb/linux/dmesg.py +++ b/scripts/gdb/linux/dmesg.py | |||
@@ -33,11 +33,12 @@ class LxDmesg(gdb.Command): | |||
33 | if log_first_idx < log_next_idx: | 33 | if log_first_idx < log_next_idx: |
34 | log_buf_2nd_half = -1 | 34 | log_buf_2nd_half = -1 |
35 | length = log_next_idx - log_first_idx | 35 | length = log_next_idx - log_first_idx |
36 | log_buf = inf.read_memory(start, length) | 36 | log_buf = utils.read_memoryview(inf, start, length).tobytes() |
37 | else: | 37 | else: |
38 | log_buf_2nd_half = log_buf_len - log_first_idx | 38 | log_buf_2nd_half = log_buf_len - log_first_idx |
39 | log_buf = inf.read_memory(start, log_buf_2nd_half) + \ | 39 | a = utils.read_memoryview(inf, start, log_buf_2nd_half) |
40 | inf.read_memory(log_buf_addr, log_next_idx) | 40 | b = utils.read_memoryview(inf, log_buf_addr, log_next_idx) |
41 | log_buf = a.tobytes() + b.tobytes() | ||
41 | 42 | ||
42 | pos = 0 | 43 | pos = 0 |
43 | while pos < log_buf.__len__(): | 44 | while pos < log_buf.__len__(): |
@@ -50,10 +51,10 @@ class LxDmesg(gdb.Command): | |||
50 | continue | 51 | continue |
51 | 52 | ||
52 | text_len = utils.read_u16(log_buf[pos + 10:pos + 12]) | 53 | text_len = utils.read_u16(log_buf[pos + 10:pos + 12]) |
53 | text = log_buf[pos + 16:pos + 16 + text_len] | 54 | text = log_buf[pos + 16:pos + 16 + text_len].decode() |
54 | time_stamp = utils.read_u64(log_buf[pos:pos + 8]) | 55 | time_stamp = utils.read_u64(log_buf[pos:pos + 8]) |
55 | 56 | ||
56 | for line in memoryview(text).tobytes().splitlines(): | 57 | for line in text.splitlines(): |
57 | gdb.write("[{time:12.6f}] {line}\n".format( | 58 | gdb.write("[{time:12.6f}] {line}\n".format( |
58 | time=time_stamp / 1000000000.0, | 59 | time=time_stamp / 1000000000.0, |
59 | line=line)) | 60 | line=line)) |
diff --git a/scripts/gdb/linux/lists.py b/scripts/gdb/linux/lists.py index 3a3775bc162b..2f335fbd86fd 100644 --- a/scripts/gdb/linux/lists.py +++ b/scripts/gdb/linux/lists.py | |||
@@ -18,6 +18,27 @@ from linux import utils | |||
18 | list_head = utils.CachedType("struct list_head") | 18 | list_head = utils.CachedType("struct list_head") |
19 | 19 | ||
20 | 20 | ||
21 | def list_for_each(head): | ||
22 | if head.type == list_head.get_type().pointer(): | ||
23 | head = head.dereference() | ||
24 | elif head.type != list_head.get_type(): | ||
25 | raise gdb.GdbError("Must be struct list_head not {}" | ||
26 | .format(head.type)) | ||
27 | |||
28 | node = head['next'].dereference() | ||
29 | while node.address != head.address: | ||
30 | yield node.address | ||
31 | node = node['next'].dereference() | ||
32 | |||
33 | |||
34 | def list_for_each_entry(head, gdbtype, member): | ||
35 | for node in list_for_each(head): | ||
36 | if node.type != list_head.get_type().pointer(): | ||
37 | raise TypeError("Type {} found. Expected struct list_head *." | ||
38 | .format(node.type)) | ||
39 | yield utils.container_of(node, gdbtype, member) | ||
40 | |||
41 | |||
21 | def list_check(head): | 42 | def list_check(head): |
22 | nb = 0 | 43 | nb = 0 |
23 | if (head.type == list_head.get_type().pointer()): | 44 | if (head.type == list_head.get_type().pointer()): |
diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py index 0a35d6dbfb80..441b23239896 100644 --- a/scripts/gdb/linux/modules.py +++ b/scripts/gdb/linux/modules.py | |||
@@ -13,7 +13,7 @@ | |||
13 | 13 | ||
14 | import gdb | 14 | import gdb |
15 | 15 | ||
16 | from linux import cpus, utils | 16 | from linux import cpus, utils, lists |
17 | 17 | ||
18 | 18 | ||
19 | module_type = utils.CachedType("struct module") | 19 | module_type = utils.CachedType("struct module") |
@@ -21,14 +21,14 @@ module_type = utils.CachedType("struct module") | |||
21 | 21 | ||
22 | def module_list(): | 22 | def module_list(): |
23 | global module_type | 23 | global module_type |
24 | modules = utils.gdb_eval_or_none("modules") | ||
25 | if modules is None: | ||
26 | return | ||
27 | |||
24 | module_ptr_type = module_type.get_type().pointer() | 28 | module_ptr_type = module_type.get_type().pointer() |
25 | modules = gdb.parse_and_eval("modules") | ||
26 | entry = modules['next'] | ||
27 | end_of_list = modules.address | ||
28 | 29 | ||
29 | while entry != end_of_list: | 30 | for module in lists.list_for_each_entry(modules, module_ptr_type, "list"): |
30 | yield utils.container_of(entry, module_ptr_type, "list") | 31 | yield module |
31 | entry = entry['next'] | ||
32 | 32 | ||
33 | 33 | ||
34 | def find_module_by_name(name): | 34 | def find_module_by_name(name): |
@@ -78,19 +78,17 @@ class LxLsmod(gdb.Command): | |||
78 | address=str(layout['base']).split()[0], | 78 | address=str(layout['base']).split()[0], |
79 | name=module['name'].string(), | 79 | name=module['name'].string(), |
80 | size=str(layout['size']), | 80 | size=str(layout['size']), |
81 | ref=str(module['refcnt']['counter']))) | 81 | ref=str(module['refcnt']['counter'] - 1))) |
82 | 82 | ||
83 | source_list = module['source_list'] | ||
84 | t = self._module_use_type.get_type().pointer() | 83 | t = self._module_use_type.get_type().pointer() |
85 | entry = source_list['next'] | ||
86 | first = True | 84 | first = True |
87 | while entry != source_list.address: | 85 | sources = module['source_list'] |
88 | use = utils.container_of(entry, t, "source_list") | 86 | for use in lists.list_for_each_entry(sources, t, "source_list"): |
89 | gdb.write("{separator}{name}".format( | 87 | gdb.write("{separator}{name}".format( |
90 | separator=" " if first else ",", | 88 | separator=" " if first else ",", |
91 | name=use['source']['name'].string())) | 89 | name=use['source']['name'].string())) |
92 | first = False | 90 | first = False |
93 | entry = entry['next'] | 91 | |
94 | gdb.write("\n") | 92 | gdb.write("\n") |
95 | 93 | ||
96 | 94 | ||
diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py index 6e6709c1830c..38b1f09d1cd9 100644 --- a/scripts/gdb/linux/proc.py +++ b/scripts/gdb/linux/proc.py | |||
@@ -12,6 +12,10 @@ | |||
12 | # | 12 | # |
13 | 13 | ||
14 | import gdb | 14 | import gdb |
15 | from linux import constants | ||
16 | from linux import utils | ||
17 | from linux import tasks | ||
18 | from linux import lists | ||
15 | 19 | ||
16 | 20 | ||
17 | class LxCmdLine(gdb.Command): | 21 | class LxCmdLine(gdb.Command): |
@@ -39,3 +43,155 @@ class LxVersion(gdb.Command): | |||
39 | gdb.write(gdb.parse_and_eval("linux_banner").string()) | 43 | gdb.write(gdb.parse_and_eval("linux_banner").string()) |
40 | 44 | ||
41 | LxVersion() | 45 | LxVersion() |
46 | |||
47 | |||
48 | # Resource Structure Printers | ||
49 | # /proc/iomem | ||
50 | # /proc/ioports | ||
51 | |||
52 | def get_resources(resource, depth): | ||
53 | while resource: | ||
54 | yield resource, depth | ||
55 | |||
56 | child = resource['child'] | ||
57 | if child: | ||
58 | for res, deep in get_resources(child, depth + 1): | ||
59 | yield res, deep | ||
60 | |||
61 | resource = resource['sibling'] | ||
62 | |||
63 | |||
64 | def show_lx_resources(resource_str): | ||
65 | resource = gdb.parse_and_eval(resource_str) | ||
66 | width = 4 if resource['end'] < 0x10000 else 8 | ||
67 | # Iterate straight to the first child | ||
68 | for res, depth in get_resources(resource['child'], 0): | ||
69 | start = int(res['start']) | ||
70 | end = int(res['end']) | ||
71 | gdb.write(" " * depth * 2 + | ||
72 | "{0:0{1}x}-".format(start, width) + | ||
73 | "{0:0{1}x} : ".format(end, width) + | ||
74 | res['name'].string() + "\n") | ||
75 | |||
76 | |||
77 | class LxIOMem(gdb.Command): | ||
78 | """Identify the IO memory resource locations defined by the kernel | ||
79 | |||
80 | Equivalent to cat /proc/iomem on a running target""" | ||
81 | |||
82 | def __init__(self): | ||
83 | super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA) | ||
84 | |||
85 | def invoke(self, arg, from_tty): | ||
86 | return show_lx_resources("iomem_resource") | ||
87 | |||
88 | LxIOMem() | ||
89 | |||
90 | |||
91 | class LxIOPorts(gdb.Command): | ||
92 | """Identify the IO port resource locations defined by the kernel | ||
93 | |||
94 | Equivalent to cat /proc/ioports on a running target""" | ||
95 | |||
96 | def __init__(self): | ||
97 | super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA) | ||
98 | |||
99 | def invoke(self, arg, from_tty): | ||
100 | return show_lx_resources("ioport_resource") | ||
101 | |||
102 | LxIOPorts() | ||
103 | |||
104 | |||
105 | # Mount namespace viewer | ||
106 | # /proc/mounts | ||
107 | |||
108 | def info_opts(lst, opt): | ||
109 | opts = "" | ||
110 | for key, string in lst.items(): | ||
111 | if opt & key: | ||
112 | opts += string | ||
113 | return opts | ||
114 | |||
115 | |||
116 | FS_INFO = {constants.LX_MS_SYNCHRONOUS: ",sync", | ||
117 | constants.LX_MS_MANDLOCK: ",mand", | ||
118 | constants.LX_MS_DIRSYNC: ",dirsync", | ||
119 | constants.LX_MS_NOATIME: ",noatime", | ||
120 | constants.LX_MS_NODIRATIME: ",nodiratime"} | ||
121 | |||
122 | MNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid", | ||
123 | constants.LX_MNT_NODEV: ",nodev", | ||
124 | constants.LX_MNT_NOEXEC: ",noexec", | ||
125 | constants.LX_MNT_NOATIME: ",noatime", | ||
126 | constants.LX_MNT_NODIRATIME: ",nodiratime", | ||
127 | constants.LX_MNT_RELATIME: ",relatime"} | ||
128 | |||
129 | mount_type = utils.CachedType("struct mount") | ||
130 | mount_ptr_type = mount_type.get_type().pointer() | ||
131 | |||
132 | |||
133 | class LxMounts(gdb.Command): | ||
134 | """Report the VFS mounts of the current process namespace. | ||
135 | |||
136 | Equivalent to cat /proc/mounts on a running target | ||
137 | An integer value can be supplied to display the mount | ||
138 | values of that process namespace""" | ||
139 | |||
140 | def __init__(self): | ||
141 | super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA) | ||
142 | |||
143 | # Equivalent to proc_namespace.c:show_vfsmnt | ||
144 | # However, that has the ability to call into s_op functions | ||
145 | # whereas we cannot and must make do with the information we can obtain. | ||
146 | def invoke(self, arg, from_tty): | ||
147 | argv = gdb.string_to_argv(arg) | ||
148 | if len(argv) >= 1: | ||
149 | try: | ||
150 | pid = int(argv[0]) | ||
151 | except: | ||
152 | raise gdb.GdbError("Provide a PID as integer value") | ||
153 | else: | ||
154 | pid = 1 | ||
155 | |||
156 | task = tasks.get_task_by_pid(pid) | ||
157 | if not task: | ||
158 | raise gdb.GdbError("Couldn't find a process with PID {}" | ||
159 | .format(pid)) | ||
160 | |||
161 | namespace = task['nsproxy']['mnt_ns'] | ||
162 | if not namespace: | ||
163 | raise gdb.GdbError("No namespace for current process") | ||
164 | |||
165 | for vfs in lists.list_for_each_entry(namespace['list'], | ||
166 | mount_ptr_type, "mnt_list"): | ||
167 | devname = vfs['mnt_devname'].string() | ||
168 | devname = devname if devname else "none" | ||
169 | |||
170 | pathname = "" | ||
171 | parent = vfs | ||
172 | while True: | ||
173 | mntpoint = parent['mnt_mountpoint'] | ||
174 | pathname = utils.dentry_name(mntpoint) + pathname | ||
175 | if (parent == parent['mnt_parent']): | ||
176 | break | ||
177 | parent = parent['mnt_parent'] | ||
178 | |||
179 | if (pathname == ""): | ||
180 | pathname = "/" | ||
181 | |||
182 | superblock = vfs['mnt']['mnt_sb'] | ||
183 | fstype = superblock['s_type']['name'].string() | ||
184 | s_flags = int(superblock['s_flags']) | ||
185 | m_flags = int(vfs['mnt']['mnt_flags']) | ||
186 | rd = "ro" if (s_flags & constants.LX_MS_RDONLY) else "rw" | ||
187 | |||
188 | gdb.write( | ||
189 | "{} {} {} {}{}{} 0 0\n" | ||
190 | .format(devname, | ||
191 | pathname, | ||
192 | fstype, | ||
193 | rd, | ||
194 | info_opts(FS_INFO, s_flags), | ||
195 | info_opts(MNT_INFO, m_flags))) | ||
196 | |||
197 | LxMounts() | ||
diff --git a/scripts/gdb/linux/radixtree.py b/scripts/gdb/linux/radixtree.py new file mode 100644 index 000000000000..0fdef4e2971a --- /dev/null +++ b/scripts/gdb/linux/radixtree.py | |||
@@ -0,0 +1,97 @@ | |||
1 | # | ||
2 | # gdb helper commands and functions for Linux kernel debugging | ||
3 | # | ||
4 | # Radix Tree Parser | ||
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 | import gdb | ||
15 | |||
16 | from linux import utils | ||
17 | from linux import constants | ||
18 | |||
19 | radix_tree_root_type = utils.CachedType("struct radix_tree_root") | ||
20 | radix_tree_node_type = utils.CachedType("struct radix_tree_node") | ||
21 | |||
22 | |||
23 | def is_indirect_ptr(node): | ||
24 | long_type = utils.get_long_type() | ||
25 | return (node.cast(long_type) & constants.LX_RADIX_TREE_INDIRECT_PTR) | ||
26 | |||
27 | |||
28 | def indirect_to_ptr(node): | ||
29 | long_type = utils.get_long_type() | ||
30 | node_type = node.type | ||
31 | indirect_ptr = node.cast(long_type) & ~constants.LX_RADIX_TREE_INDIRECT_PTR | ||
32 | return indirect_ptr.cast(node_type) | ||
33 | |||
34 | |||
35 | def maxindex(height): | ||
36 | height = height & constants.LX_RADIX_TREE_HEIGHT_MASK | ||
37 | return gdb.parse_and_eval("height_to_maxindex["+str(height)+"]") | ||
38 | |||
39 | |||
40 | def lookup(root, index): | ||
41 | if root.type == radix_tree_root_type.get_type().pointer(): | ||
42 | root = root.dereference() | ||
43 | elif root.type != radix_tree_root_type.get_type(): | ||
44 | raise gdb.GdbError("Must be struct radix_tree_root not {}" | ||
45 | .format(root.type)) | ||
46 | |||
47 | node = root['rnode'] | ||
48 | if node is 0: | ||
49 | return None | ||
50 | |||
51 | if not (is_indirect_ptr(node)): | ||
52 | if (index > 0): | ||
53 | return None | ||
54 | return node | ||
55 | |||
56 | node = indirect_to_ptr(node) | ||
57 | |||
58 | height = node['path'] & constants.LX_RADIX_TREE_HEIGHT_MASK | ||
59 | if (index > maxindex(height)): | ||
60 | return None | ||
61 | |||
62 | shift = (height-1) * constants.LX_RADIX_TREE_MAP_SHIFT | ||
63 | |||
64 | while True: | ||
65 | new_index = (index >> shift) & constants.LX_RADIX_TREE_MAP_MASK | ||
66 | slot = node['slots'][new_index] | ||
67 | |||
68 | node = slot.cast(node.type.pointer()).dereference() | ||
69 | if node is 0: | ||
70 | return None | ||
71 | |||
72 | shift -= constants.LX_RADIX_TREE_MAP_SHIFT | ||
73 | height -= 1 | ||
74 | |||
75 | if (height <= 0): | ||
76 | break | ||
77 | |||
78 | return node | ||
79 | |||
80 | |||
81 | class LxRadixTree(gdb.Function): | ||
82 | """ Lookup and return a node from a RadixTree. | ||
83 | |||
84 | $lx_radix_tree_lookup(root_node [, index]): Return the node at the given index. | ||
85 | If index is omitted, the root node is dereferenced and returned.""" | ||
86 | |||
87 | def __init__(self): | ||
88 | super(LxRadixTree, self).__init__("lx_radix_tree_lookup") | ||
89 | |||
90 | def invoke(self, root, index=0): | ||
91 | result = lookup(root, index) | ||
92 | if result is None: | ||
93 | raise gdb.GdbError("No entry in tree at index {}".format(index)) | ||
94 | |||
95 | return result | ||
96 | |||
97 | LxRadixTree() | ||
diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py index 862a4ae24d49..1bf949c43b76 100644 --- a/scripts/gdb/linux/tasks.py +++ b/scripts/gdb/linux/tasks.py | |||
@@ -114,3 +114,22 @@ variable.""" | |||
114 | 114 | ||
115 | 115 | ||
116 | LxThreadInfoFunc() | 116 | LxThreadInfoFunc() |
117 | |||
118 | |||
119 | class LxThreadInfoByPidFunc (gdb.Function): | ||
120 | """Calculate Linux thread_info from task variable found by pid | ||
121 | |||
122 | $lx_thread_info_by_pid(PID): Given PID, return the corresponding thread_info | ||
123 | variable.""" | ||
124 | |||
125 | def __init__(self): | ||
126 | super(LxThreadInfoByPidFunc, self).__init__("lx_thread_info_by_pid") | ||
127 | |||
128 | def invoke(self, pid): | ||
129 | task = get_task_by_pid(pid) | ||
130 | if task: | ||
131 | return get_thread_info(task.dereference()) | ||
132 | else: | ||
133 | raise gdb.GdbError("No task of PID " + str(pid)) | ||
134 | |||
135 | LxThreadInfoByPidFunc() | ||
diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py index 0893b326a28b..50805874cfc3 100644 --- a/scripts/gdb/linux/utils.py +++ b/scripts/gdb/linux/utils.py | |||
@@ -87,11 +87,24 @@ def get_target_endianness(): | |||
87 | return target_endianness | 87 | return target_endianness |
88 | 88 | ||
89 | 89 | ||
90 | def read_memoryview(inf, start, length): | ||
91 | return memoryview(inf.read_memory(start, length)) | ||
92 | |||
93 | |||
90 | def read_u16(buffer): | 94 | def read_u16(buffer): |
95 | value = [0, 0] | ||
96 | |||
97 | if type(buffer[0]) is str: | ||
98 | value[0] = ord(buffer[0]) | ||
99 | value[1] = ord(buffer[1]) | ||
100 | else: | ||
101 | value[0] = buffer[0] | ||
102 | value[1] = buffer[1] | ||
103 | |||
91 | if get_target_endianness() == LITTLE_ENDIAN: | 104 | if get_target_endianness() == LITTLE_ENDIAN: |
92 | return ord(buffer[0]) + (ord(buffer[1]) << 8) | 105 | return value[0] + (value[1] << 8) |
93 | else: | 106 | else: |
94 | return ord(buffer[1]) + (ord(buffer[0]) << 8) | 107 | return value[1] + (value[0] << 8) |
95 | 108 | ||
96 | 109 | ||
97 | def read_u32(buffer): | 110 | def read_u32(buffer): |
@@ -154,3 +167,18 @@ def get_gdbserver_type(): | |||
154 | if gdbserver_type is not None and hasattr(gdb, 'events'): | 167 | if gdbserver_type is not None and hasattr(gdb, 'events'): |
155 | gdb.events.exited.connect(exit_handler) | 168 | gdb.events.exited.connect(exit_handler) |
156 | return gdbserver_type | 169 | return gdbserver_type |
170 | |||
171 | |||
172 | def gdb_eval_or_none(expresssion): | ||
173 | try: | ||
174 | return gdb.parse_and_eval(expresssion) | ||
175 | except: | ||
176 | return None | ||
177 | |||
178 | |||
179 | def dentry_name(d): | ||
180 | parent = d['d_parent'] | ||
181 | if parent == d or parent == 0: | ||
182 | return "" | ||
183 | p = dentry_name(d['d_parent']) + "/" | ||
184 | return p + d['d_iname'].string() | ||
diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py index d5943eca19cd..3a80ad6eecad 100644 --- a/scripts/gdb/vmlinux-gdb.py +++ b/scripts/gdb/vmlinux-gdb.py | |||
@@ -30,3 +30,5 @@ else: | |||
30 | import linux.cpus | 30 | import linux.cpus |
31 | import linux.lists | 31 | import linux.lists |
32 | import linux.proc | 32 | import linux.proc |
33 | import linux.constants | ||
34 | import linux.radixtree | ||