From 7704d58a8509c65e3f7e4407ca2e5fa6360349c1 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:47:07 -0800 Subject: scripts/gdb: add task iteration class This class allows to iterate over all tasks 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/tasks.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 scripts/gdb/linux/tasks.py (limited to 'scripts/gdb/linux/tasks.py') diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py new file mode 100644 index 000000000000..cd259846ab4b --- /dev/null +++ b/scripts/gdb/linux/tasks.py @@ -0,0 +1,46 @@ +# +# gdb helper commands and functions for Linux kernel debugging +# +# task & thread 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 utils + + +task_type = utils.CachedType("struct task_struct") + + +class TaskList: + def __init__(self): + global task_type + self.task_ptr_type = task_type.get_type().pointer() + self.init_task = gdb.parse_and_eval("init_task") + self.curr_group = self.init_task.address + self.curr_task = None + + def __iter__(self): + return self + + def next(self): + t = self.curr_task + if not t or t == self.curr_group: + self.curr_group = \ + utils.container_of(self.curr_group['tasks']['next'], + self.task_ptr_type, "tasks") + if self.curr_group == self.init_task.address: + raise StopIteration + t = self.curr_task = self.curr_group + else: + self.curr_task = \ + utils.container_of(t['thread_group']['next'], + self.task_ptr_type, "thread_group") + return t -- cgit v1.2.2 From 4752871081ba4fbb3c539488a95e77d8011bfe49 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:47:10 -0800 Subject: scripts/gdb: add helper and convenience function to look up tasks Add the helper task_by_pid that can look up a task by its PID. Also export it 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/tasks.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'scripts/gdb/linux/tasks.py') diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py index cd259846ab4b..13bb97cd3312 100644 --- a/scripts/gdb/linux/tasks.py +++ b/scripts/gdb/linux/tasks.py @@ -44,3 +44,30 @@ class TaskList: utils.container_of(t['thread_group']['next'], self.task_ptr_type, "thread_group") return t + + +def get_task_by_pid(pid): + for task in TaskList(): + if int(task['pid']) == pid: + return task + return None + + +class LxTaskByPidFunc(gdb.Function): + """Find Linux task by PID and return the task_struct variable. + +$lx_task_by_pid(PID): Given PID, iterate over all tasks of the target and +return that task_struct variable which PID matches.""" + + def __init__(self): + super(LxTaskByPidFunc, self).__init__("lx_task_by_pid") + + def invoke(self, pid): + task = get_task_by_pid(pid) + if task: + return task.dereference() + else: + raise gdb.GdbError("No task of PID " + str(pid)) + + +LxTaskByPidFunc() -- cgit v1.2.2 From cf7492e933c0df200f8fa46c3684e8bd20890ab2 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 17 Feb 2015 13:47:15 -0800 Subject: scripts/gdb: add internal helper and convenience function to retrieve thread_info Add the internal helper get_thread_info that calculates the thread_info from a given task variable. Also export this service as a convenience function. Note: ia64 version is untested. Signed-off-by: Jan Kiszka Cc: Tony Luck Cc: Fenghua Yu 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/tasks.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'scripts/gdb/linux/tasks.py') diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py index 13bb97cd3312..63cd6c517e6d 100644 --- a/scripts/gdb/linux/tasks.py +++ b/scripts/gdb/linux/tasks.py @@ -71,3 +71,38 @@ return that task_struct variable which PID matches.""" LxTaskByPidFunc() + + +thread_info_type = utils.CachedType("struct thread_info") + +ia64_task_size = None + + +def get_thread_info(task): + global thread_info_type + thread_info_ptr_type = thread_info_type.get_type().pointer() + if utils.is_target_arch("ia64"): + global ia64_task_size + if ia64_task_size is None: + ia64_task_size = gdb.parse_and_eval("sizeof(struct task_struct)") + thread_info_addr = task.address + ia64_task_size + thread_info = thread_info_addr.cast(thread_info_ptr_type) + else: + thread_info = task['stack'].cast(thread_info_ptr_type) + return thread_info.dereference() + + +class LxThreadInfoFunc (gdb.Function): + """Calculate Linux thread_info from task variable. + +$lx_thread_info(TASK): Given TASK, return the corresponding thread_info +variable.""" + + def __init__(self): + super(LxThreadInfoFunc, self).__init__("lx_thread_info") + + def invoke(self, task): + return get_thread_info(task) + + +LxThreadInfoFunc() -- cgit v1.2.2 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/tasks.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'scripts/gdb/linux/tasks.py') 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(): -- cgit v1.2.2 From 54e2289a34e13d956acb841a00c3a6f06aced3f9 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 17 Feb 2015 13:47:41 -0800 Subject: scripts/gdb: use a generator instead of iterator for task list The iterator does not return any task_struct from the thread_group list because the first condition in the 'if not t or ...' will only be the first time None. Instead of keeping track of the state ourself in the next() function, we fall back using Python's generator. Signed-off-by: Daniel Wagner 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/tasks.py | 50 +++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) (limited to 'scripts/gdb/linux/tasks.py') diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py index 0008e75f1c4f..e2037d9bb7eb 100644 --- a/scripts/gdb/linux/tasks.py +++ b/scripts/gdb/linux/tasks.py @@ -18,38 +18,28 @@ from linux import utils task_type = utils.CachedType("struct task_struct") - -class TaskList: - def __init__(self): - global task_type - self.task_ptr_type = task_type.get_type().pointer() - self.init_task = gdb.parse_and_eval("init_task") - self.curr_group = self.init_task.address - self.curr_task = None - - def __iter__(self): - return self - - def __next__(self): - t = self.curr_task - if not t or t == self.curr_group: - self.curr_group = \ - utils.container_of(self.curr_group['tasks']['next'], - self.task_ptr_type, "tasks") - if self.curr_group == self.init_task.address: - raise StopIteration - t = self.curr_task = self.curr_group - else: - self.curr_task = \ - utils.container_of(t['thread_group']['next'], - self.task_ptr_type, "thread_group") - return t - - def next(self): - return self.__next__() +def task_lists(): + global task_type + task_ptr_type = task_type.get_type().pointer() + init_task = gdb.parse_and_eval("init_task").address + t = g = init_task + + while True: + while True: + yield t + + t = utils.container_of(t['thread_group']['next'], + task_ptr_type, "thread_group") + if t == g: + break + + t = g = utils.container_of(g['tasks']['next'], + task_ptr_type, "tasks") + if t == init_task: + return def get_task_by_pid(pid): - for task in TaskList(): + for task in task_lists(): if int(task['pid']) == pid: return task return None -- cgit v1.2.2