#
# gdb helper commands and functions for Linux kernel debugging
#
#  task & thread tools
#
# Copyright (c) Siemens AG, 2011-2013
#
# Authors:
#  Jan Kiszka <jan.kiszka@siemens.com>
#
# This work is licensed under the terms of the GNU GPL version 2.
#

import gdb

from linux import utils, lists


task_type = utils.CachedType("struct task_struct")


def task_lists():
    task_ptr_type = task_type.get_type().pointer()
    init_task = gdb.parse_and_eval("init_task").address
    t = init_task

    while True:
        thread_head = t['signal']['thread_head']
        for thread in lists.list_for_each_entry(thread_head, task_ptr_type, 'thread_node'):
            yield thread

        t = utils.container_of(t['tasks']['next'],
                               task_ptr_type, "tasks")
        if t == init_task:
            return


def get_task_by_pid(pid):
    for task in task_lists():
        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()


class LxPs(gdb.Command):
    """Dump Linux tasks."""

    def __init__(self):
        super(LxPs, self).__init__("lx-ps", gdb.COMMAND_DATA)

    def invoke(self, arg, from_tty):
        gdb.write("{:>10} {:>12} {:>7}\n".format("TASK", "PID", "COMM"))
        for task in task_lists():
            gdb.write("{} {:^5} {}\n".format(
                task.format_string().split()[0],
                task["pid"].format_string(),
                task["comm"].string()))


LxPs()


thread_info_type = utils.CachedType("struct thread_info")


def get_thread_info(task):
    thread_info_ptr_type = thread_info_type.get_type().pointer()
    if task.type.fields()[0].type == thread_info_type.get_type():
        return task['thread_info']
    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()


class LxThreadInfoByPidFunc (gdb.Function):
    """Calculate Linux thread_info from task variable found by pid

$lx_thread_info_by_pid(PID): Given PID, return the corresponding thread_info
variable."""

    def __init__(self):
        super(LxThreadInfoByPidFunc, self).__init__("lx_thread_info_by_pid")

    def invoke(self, pid):
        task = get_task_by_pid(pid)
        if task:
            return get_thread_info(task.dereference())
        else:
            raise gdb.GdbError("No task of PID " + str(pid))


LxThreadInfoByPidFunc()
