From fe7f9ed98dad611ceaf17403f1c5bfd016eadcaa Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:47:21 -0800 Subject: scripts/gdb: add internal helper and convenience function for per-cpu lookup This function allows to obtain a per-cpu variable, either of the current or an explicitly specified CPU. Note: sparc64 version is untested. Signed-off-by: Jan Kiszka Cc: "David S. Miller" 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 | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 scripts/gdb/linux/cpus.py (limited to 'scripts/gdb/linux/cpus.py') diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py new file mode 100644 index 000000000000..18337e01ddef --- /dev/null +++ b/scripts/gdb/linux/cpus.py @@ -0,0 +1,68 @@ +# +# gdb helper commands and functions for Linux kernel debugging +# +# per-cpu tools +# +# Copyright (c) Siemens AG, 2011-2013 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL version 2. +# + +import gdb + +from linux import tasks, utils + + +MAX_CPUS = 4096 + + +def get_current_cpu(): + if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU: + return gdb.selected_thread().num - 1 + elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB: + tid = gdb.selected_thread().ptid[2] + if tid > (0x100000000 - MAX_CPUS - 2): + return 0x100000000 - tid - 2 + else: + return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu'] + else: + raise gdb.GdbError("Sorry, obtaining the current CPU is not yet " + "supported with this gdb server.") + + +def per_cpu(var_ptr, cpu): + if cpu == -1: + cpu = get_current_cpu() + if utils.is_target_arch("sparc:v9"): + offset = gdb.parse_and_eval( + "trap_block[{0}].__per_cpu_base".format(str(cpu))) + else: + try: + offset = gdb.parse_and_eval( + "__per_cpu_offset[{0}]".format(str(cpu))) + except gdb.error: + # !CONFIG_SMP case + offset = 0 + pointer = var_ptr.cast(utils.get_long_type()) + offset + return pointer.cast(var_ptr.type).dereference() + + +class PerCpu(gdb.Function): + """Return per-cpu variable. + +$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the +given CPU number. If CPU is omitted, the CPU of the current context is used. +Note that VAR has to be quoted as string.""" + + def __init__(self): + super(PerCpu, self).__init__("lx_per_cpu") + + def invoke(self, var_name, cpu=-1): + var_ptr = gdb.parse_and_eval("&" + var_name.string()) + return per_cpu(var_ptr, cpu) + + +PerCpu() -- cgit v1.2.3 From 116b47b4da037547585cebe4e3275ef68905d509 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:47:24 -0800 Subject: scripts/gdb: add lx_current convenience function This is a shorthand for *$lx_per_cpu("current_task"), i.e. a convenience function to retrieve the currently running task of the active context. 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 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'scripts/gdb/linux/cpus.py') diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py index 18337e01ddef..b683da92f194 100644 --- a/scripts/gdb/linux/cpus.py +++ b/scripts/gdb/linux/cpus.py @@ -66,3 +66,20 @@ Note that VAR has to be quoted as string.""" PerCpu() + + +class LxCurrentFunc(gdb.Function): + """Return current task. + +$lx_current([CPU]): Return the per-cpu task variable for the given CPU +number. If CPU is omitted, the CPU of the current context is used.""" + + def __init__(self): + super(LxCurrentFunc, self).__init__("lx_current") + + def invoke(self, cpu=-1): + var_ptr = gdb.parse_and_eval("¤t_task") + return per_cpu(var_ptr, cpu).dereference() + + +LxCurrentFunc() -- cgit v1.2.3 From 3d4cd9c94191f60cbb741cfbaa770d442c4680aa Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:47:27 -0800 Subject: scripts/gdb: add class to iterate over CPU masks Will be used first to count module references. It is optimized to read the mask only once per stop. 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 | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'scripts/gdb/linux/cpus.py') diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py index b683da92f194..c1441f23c0c2 100644 --- a/scripts/gdb/linux/cpus.py +++ b/scripts/gdb/linux/cpus.py @@ -50,6 +50,60 @@ def per_cpu(var_ptr, cpu): return pointer.cast(var_ptr.type).dereference() +cpu_mask = {} + + +def cpu_mask_invalidate(event): + global cpu_mask + cpu_mask = {} + gdb.events.stop.disconnect(cpu_mask_invalidate) + if hasattr(gdb.events, 'new_objfile'): + 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 + break + + while self.bits & 1 == 0: + self.bits >>= 1 + self.bit += 1 + + cpu = self.entry * self.bits_per_entry + self.bit + + self.bits >>= 1 + self.bit += 1 + + return cpu + + class PerCpu(gdb.Function): """Return per-cpu variable. -- cgit v1.2.3 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/cpus.py') diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py index c1441f23c0c2..8045871e2840 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 7650f240ebcc..3c947f0c5dad 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 e7c99e9c9620..2dbf6796ce4f 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 139841fa7f70..ae757fdf5ce6 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 63cd6c517e6d..0008e75f1c4f 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 a4a16403dc56..128c306db3ee 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 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/cpus.py') diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py index 8045871e2840..4297b83fedef 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 6d497229d026..a1504c4f1900 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