From 850202e17df68c51593bab36a26c8d9279f8c029 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:46:44 -0800 Subject: scripts/gdb: add module iteration class Will soon be used for loading symbols, printing global variables or listing modules. Signed-off-by: Jan Kiszka Cc: Thomas Gleixner Cc: Jason Wessel Cc: Andi Kleen Cc: Ben Widawsky Cc: Borislav Petkov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/gdb/linux/modules.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 scripts/gdb/linux/modules.py (limited to 'scripts/gdb/linux/modules.py') diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py new file mode 100644 index 00000000000..8a65c3d5eec --- /dev/null +++ b/scripts/gdb/linux/modules.py @@ -0,0 +1,39 @@ +# +# gdb helper commands and functions for Linux kernel debugging +# +# module tools +# +# Copyright (c) Siemens AG, 2013 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL version 2. +# + +import gdb + +from linux import utils + + +module_type = utils.CachedType("struct module") + + +class ModuleList: + def __init__(self): + global module_type + self.module_ptr_type = module_type.get_type().pointer() + modules = gdb.parse_and_eval("modules") + self.curr_entry = modules['next'] + self.end_of_list = modules.address + + def __iter__(self): + return self + + def next(self): + entry = self.curr_entry + if entry != self.end_of_list: + self.curr_entry = entry['next'] + return utils.container_of(entry, self.module_ptr_type, "list") + else: + raise StopIteration -- cgit v1.2.3-70-g09d2 From 7b599ef535a7faef53034fb7fb150b61057efe28 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:46:55 -0800 Subject: scripts/gdb: add internal helper and convenience function to look up a module Add the internal helper get_module_by_name to obtain the module structure corresponding to the given name. Also export this service as a convenience function. Signed-off-by: Jan Kiszka Cc: Thomas Gleixner Cc: Jason Wessel Cc: Andi Kleen Cc: Ben Widawsky Cc: Borislav Petkov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/gdb/linux/modules.py | 28 ++++++++++++++++++++++++++++ scripts/gdb/vmlinux-gdb.py | 1 + 2 files changed, 29 insertions(+) (limited to 'scripts/gdb/linux/modules.py') diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py index 8a65c3d5eec..531f7632d03 100644 --- a/scripts/gdb/linux/modules.py +++ b/scripts/gdb/linux/modules.py @@ -37,3 +37,31 @@ class ModuleList: return utils.container_of(entry, self.module_ptr_type, "list") else: raise StopIteration + + +def find_module_by_name(name): + for module in ModuleList(): + if module['name'].string() == name: + return module + return None + + +class LxModule(gdb.Function): + """Find module by name and return the module variable. + +$lx_module("MODULE"): Given the name MODULE, iterate over all loaded modules +of the target and return that module variable which MODULE matches.""" + + def __init__(self): + super(LxModule, self).__init__("lx_module") + + def invoke(self, mod_name): + mod_name = mod_name.string() + module = find_module_by_name(mod_name) + if module: + return module.dereference() + else: + raise gdb.GdbError("Unable to find MODULE " + mod_name) + + +LxModule() diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py index 0b0faa4cb5a..cf2e7161b28 100644 --- a/scripts/gdb/vmlinux-gdb.py +++ b/scripts/gdb/vmlinux-gdb.py @@ -24,3 +24,4 @@ except: else: import linux.utils import linux.symbols + import linux.modules -- cgit v1.2.3-70-g09d2 From 5403727f985ba39967c899a56fff5bbd2c9a9f36 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:47:29 -0800 Subject: scripts/gdb: add lx-lsmod command This adds a lsmod-like command to list all currently loaded modules of the target. Signed-off-by: Jan Kiszka Cc: Thomas Gleixner Cc: Jason Wessel Cc: Andi Kleen Cc: Ben Widawsky Cc: Borislav Petkov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/gdb/linux/modules.py | 46 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'scripts/gdb/linux/modules.py') diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py index 531f7632d03..e7c99e9c962 100644 --- a/scripts/gdb/linux/modules.py +++ b/scripts/gdb/linux/modules.py @@ -13,7 +13,7 @@ import gdb -from linux import utils +from linux import cpus, utils module_type = utils.CachedType("struct module") @@ -65,3 +65,47 @@ of the target and return that module variable which MODULE matches.""" LxModule() + + +class LxLsmod(gdb.Command): + """List currently loaded modules.""" + + _module_use_type = utils.CachedType("struct module_use") + + def __init__(self): + super(LxLsmod, self).__init__("lx-lsmod", gdb.COMMAND_DATA) + + def invoke(self, arg, from_tty): + gdb.write( + "Address{0} Module Size Used by\n".format( + " " if utils.get_long_type().sizeof == 8 else "")) + + for module in ModuleList(): + ref = 0 + module_refptr = module['refptr'] + for cpu in cpus.CpuList("cpu_possible_mask"): + refptr = cpus.per_cpu(module_refptr, cpu) + ref += refptr['incs'] + ref -= refptr['decs'] + + gdb.write("{address} {name:<19} {size:>8} {ref}".format( + address=str(module['module_core']).split()[0], + name=module['name'].string(), + size=module['core_size'], + ref=ref)) + + source_list = module['source_list'] + t = self._module_use_type.get_type().pointer() + entry = source_list['next'] + first = True + while entry != source_list.address: + use = utils.container_of(entry, t, "source_list") + gdb.write("{separator}{name}".format( + separator=" " if first else ",", + name=use['source']['name'].string())) + first = False + entry = entry['next'] + gdb.write("\n") + + +LxLsmod() -- cgit v1.2.3-70-g09d2 From 276d97d90a2485f9a830a7a8242e4317b24c896f Mon Sep 17 00:00:00 2001 From: Pantelis Koukousoulas Date: Tue, 17 Feb 2015 13:47:35 -0800 Subject: scripts/gdb: port to python3 / gdb7.7 I tried to use these scripts in an ubuntu 14.04 host (gdb 7.7 compiled against python 3.3) but there were several errors. I believe this patch fixes these issues so that the commands now work (I tested lx-symbols, lx-dmesg, lx-lsmod). Main issues that needed to be resolved: * In python 2 iterators have a "next()" method. In python 3 it is __next__() instead (so let's just add both). * In older python versions there was an implicit conversion in object.__format__() (used when an object is in string.format()) where it was converting the object to str first and then calling str's __format__(). This has now been removed so we must explicitly convert to str the objects for which we need to keep this behavior. * In dmesg.py: in python 3 log_buf is now a "memoryview" object which needs to be converted to a string in order to use string methods like "splitlines()". Luckily memoryview exists in python 2.7.6 as well, so we can convert log_buf to memoryview and use the same code in both python 2 and python 3. This version of the patch has now been tested with gdb 7.7 and both python 3.4 and python 2.7.6 (I think asking for at least python 2.7.6 is a reasonable requirement instead of complicating the code with version checks etc). Signed-off-by: Pantelis Koukousoulas Signed-off-by: Jan Kiszka Cc: Thomas Gleixner Cc: Jason Wessel Cc: Andi Kleen Cc: Ben Widawsky Cc: Borislav Petkov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/gdb/linux/cpus.py | 5 ++++- scripts/gdb/linux/dmesg.py | 3 ++- scripts/gdb/linux/modules.py | 9 ++++++--- scripts/gdb/linux/symbols.py | 4 ++-- scripts/gdb/linux/tasks.py | 4 +++- scripts/gdb/linux/utils.py | 2 +- 6 files changed, 18 insertions(+), 9 deletions(-) (limited to 'scripts/gdb/linux/modules.py') diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py index c1441f23c0c..8045871e284 100644 --- a/scripts/gdb/linux/cpus.py +++ b/scripts/gdb/linux/cpus.py @@ -82,7 +82,7 @@ class CpuList(): def __iter__(self): return self - def next(self): + def __next__(self): while self.bits == 0: self.entry += 1 if self.entry == self.num_entries: @@ -103,6 +103,9 @@ class CpuList(): return cpu + def next(self): + return self.__next__() + class PerCpu(gdb.Function): """Return per-cpu variable. diff --git a/scripts/gdb/linux/dmesg.py b/scripts/gdb/linux/dmesg.py index 7650f240ebc..3c947f0c5da 100644 --- a/scripts/gdb/linux/dmesg.py +++ b/scripts/gdb/linux/dmesg.py @@ -51,9 +51,10 @@ class LxDmesg(gdb.Command): continue text_len = utils.read_u16(log_buf[pos + 10:pos + 12]) + text = log_buf[pos + 16:pos + 16 + text_len] time_stamp = utils.read_u64(log_buf[pos:pos + 8]) - for line in log_buf[pos + 16:pos + 16 + text_len].splitlines(): + for line in memoryview(text).tobytes().splitlines(): gdb.write("[{time:12.6f}] {line}\n".format( time=time_stamp / 1000000000.0, line=line)) diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py index e7c99e9c962..2dbf6796ce4 100644 --- a/scripts/gdb/linux/modules.py +++ b/scripts/gdb/linux/modules.py @@ -30,7 +30,7 @@ class ModuleList: def __iter__(self): return self - def next(self): + def __next__(self): entry = self.curr_entry if entry != self.end_of_list: self.curr_entry = entry['next'] @@ -38,6 +38,9 @@ class ModuleList: else: raise StopIteration + def next(self): + return self.__next__() + def find_module_by_name(name): for module in ModuleList(): @@ -91,8 +94,8 @@ class LxLsmod(gdb.Command): gdb.write("{address} {name:<19} {size:>8} {ref}".format( address=str(module['module_core']).split()[0], name=module['name'].string(), - size=module['core_size'], - ref=ref)) + size=str(module['core_size']), + ref=str(ref))) source_list = module['source_list'] t = self._module_use_type.get_type().pointer() diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py index 139841fa7f7..ae757fdf5ce 100644 --- a/scripts/gdb/linux/symbols.py +++ b/scripts/gdb/linux/symbols.py @@ -73,7 +73,7 @@ lx-symbols command.""" def _get_module_file(self, module_name): module_pattern = ".*/{0}\.ko$".format( - string.replace(module_name, "_", r"[_\-]")) + module_name.replace("_", r"[_\-]")) for name in self.module_files: if re.match(module_pattern, name) and os.path.exists(name): return name @@ -87,7 +87,7 @@ lx-symbols command.""" attrs = sect_attrs['attrs'] section_name_to_address = { attrs[n]['name'].string() : attrs[n]['address'] - for n in range(sect_attrs['nsections'])} + for n in range(int(sect_attrs['nsections']))} args = [] for section_name in [".data", ".data..read_mostly", ".rodata", ".bss"]: address = section_name_to_address.get(section_name) diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py index 63cd6c517e6..0008e75f1c4 100644 --- a/scripts/gdb/linux/tasks.py +++ b/scripts/gdb/linux/tasks.py @@ -30,7 +30,7 @@ class TaskList: def __iter__(self): return self - def next(self): + def __next__(self): t = self.curr_task if not t or t == self.curr_group: self.curr_group = \ @@ -45,6 +45,8 @@ class TaskList: self.task_ptr_type, "thread_group") return t + def next(self): + return self.__next__() def get_task_by_pid(pid): for task in TaskList(): diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py index a4a16403dc5..128c306db3e 100644 --- a/scripts/gdb/linux/utils.py +++ b/scripts/gdb/linux/utils.py @@ -83,7 +83,7 @@ def get_target_endianness(): elif "big endian" in endian: target_endianness = BIG_ENDIAN else: - raise gdb.GdgError("unknown endianness '{0}'".format(endian)) + raise gdb.GdgError("unknown endianness '{0}'".format(str(endian))) return target_endianness -- cgit v1.2.3-70-g09d2 From fffb944c4e6d3882a7a15c494bd4cde36c68c39c Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:47:44 -0800 Subject: scripts/gdb: convert ModuleList to generator function Analogously to the task list, convert the module list to a generator function. It noticeably simplifies the code. Signed-off-by: Jan Kiszka Cc: Thomas Gleixner Cc: Jason Wessel Cc: Andi Kleen Cc: Ben Widawsky Cc: Borislav Petkov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/gdb/linux/modules.py | 33 +++++++++++---------------------- scripts/gdb/linux/symbols.py | 2 +- 2 files changed, 12 insertions(+), 23 deletions(-) (limited to 'scripts/gdb/linux/modules.py') diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py index 2dbf6796ce4..6d497229d02 100644 --- a/scripts/gdb/linux/modules.py +++ b/scripts/gdb/linux/modules.py @@ -19,31 +19,20 @@ from linux import cpus, utils module_type = utils.CachedType("struct module") -class ModuleList: - def __init__(self): - global module_type - self.module_ptr_type = module_type.get_type().pointer() - modules = gdb.parse_and_eval("modules") - self.curr_entry = modules['next'] - self.end_of_list = modules.address - - def __iter__(self): - return self - - def __next__(self): - entry = self.curr_entry - if entry != self.end_of_list: - self.curr_entry = entry['next'] - return utils.container_of(entry, self.module_ptr_type, "list") - else: - raise StopIteration +def module_list(): + global module_type + module_ptr_type = module_type.get_type().pointer() + modules = gdb.parse_and_eval("modules") + entry = modules['next'] + end_of_list = modules.address - def next(self): - return self.__next__() + while entry != end_of_list: + yield utils.container_of(entry, module_ptr_type, "list") + entry = entry['next'] def find_module_by_name(name): - for module in ModuleList(): + for module in module_list(): if module['name'].string() == name: return module return None @@ -83,7 +72,7 @@ class LxLsmod(gdb.Command): "Address{0} Module Size Used by\n".format( " " if utils.get_long_type().sizeof == 8 else "")) - for module in ModuleList(): + for module in module_list(): ref = 0 module_refptr = module['refptr'] for cpu in cpus.CpuList("cpu_possible_mask"): diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py index ae757fdf5ce..bf05e451c58 100644 --- a/scripts/gdb/linux/symbols.py +++ b/scripts/gdb/linux/symbols.py @@ -133,7 +133,7 @@ lx-symbols command.""" gdb.execute("symbol-file vmlinux") self.loaded_modules = [] - module_list = modules.ModuleList() + module_list = modules.module_list() if not module_list: gdb.write("no modules found\n") else: -- cgit v1.2.3-70-g09d2 From a77e15e8b4ccaf43b3a527cbb882bf816c5a629d Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:47:47 -0800 Subject: scripts/gdb: convert CpuList to generator function Yet another code simplification. Signed-off-by: Jan Kiszka Cc: Thomas Gleixner Cc: Jason Wessel Cc: Andi Kleen Cc: Ben Widawsky Cc: Borislav Petkov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/gdb/linux/cpus.py | 71 ++++++++++++++++++++------------------------ scripts/gdb/linux/modules.py | 2 +- 2 files changed, 33 insertions(+), 40 deletions(-) (limited to 'scripts/gdb/linux/modules.py') diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py index 8045871e284..4297b83fede 100644 --- a/scripts/gdb/linux/cpus.py +++ b/scripts/gdb/linux/cpus.py @@ -61,50 +61,43 @@ def cpu_mask_invalidate(event): gdb.events.new_objfile.disconnect(cpu_mask_invalidate) -class CpuList(): - def __init__(self, mask_name): - global cpu_mask - self.mask = None - if mask_name in cpu_mask: - self.mask = cpu_mask[mask_name] - if self.mask is None: - self.mask = gdb.parse_and_eval(mask_name + ".bits") - if hasattr(gdb, 'events'): - cpu_mask[mask_name] = self.mask - gdb.events.stop.connect(cpu_mask_invalidate) - if hasattr(gdb.events, 'new_objfile'): - gdb.events.new_objfile.connect(cpu_mask_invalidate) - self.bits_per_entry = self.mask[0].type.sizeof * 8 - self.num_entries = self.mask.type.sizeof * 8 / self.bits_per_entry - self.entry = -1 - self.bits = 0 - - def __iter__(self): - return self - - def __next__(self): - while self.bits == 0: - self.entry += 1 - if self.entry == self.num_entries: - raise StopIteration - self.bits = self.mask[self.entry] - if self.bits != 0: - self.bit = 0 +def cpu_list(mask_name): + global cpu_mask + mask = None + if mask_name in cpu_mask: + mask = cpu_mask[mask_name] + if mask is None: + mask = gdb.parse_and_eval(mask_name + ".bits") + if hasattr(gdb, 'events'): + cpu_mask[mask_name] = mask + gdb.events.stop.connect(cpu_mask_invalidate) + if hasattr(gdb.events, 'new_objfile'): + gdb.events.new_objfile.connect(cpu_mask_invalidate) + bits_per_entry = mask[0].type.sizeof * 8 + num_entries = mask.type.sizeof * 8 / bits_per_entry + entry = -1 + bits = 0 + + while True: + while bits == 0: + entry += 1 + if entry == num_entries: + return + bits = mask[entry] + if bits != 0: + bit = 0 break - while self.bits & 1 == 0: - self.bits >>= 1 - self.bit += 1 - - cpu = self.entry * self.bits_per_entry + self.bit + while bits & 1 == 0: + bits >>= 1 + bit += 1 - self.bits >>= 1 - self.bit += 1 + cpu = entry * bits_per_entry + bit - return cpu + bits >>= 1 + bit += 1 - def next(self): - return self.__next__() + yield cpu class PerCpu(gdb.Function): diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py index 6d497229d02..a1504c4f190 100644 --- a/scripts/gdb/linux/modules.py +++ b/scripts/gdb/linux/modules.py @@ -75,7 +75,7 @@ class LxLsmod(gdb.Command): for module in module_list(): ref = 0 module_refptr = module['refptr'] - for cpu in cpus.CpuList("cpu_possible_mask"): + for cpu in cpus.cpu_list("cpu_possible_mask"): refptr = cpus.per_cpu(module_refptr, cpu) ref += refptr['incs'] ref -= refptr['decs'] -- cgit v1.2.3-70-g09d2