From d46b8b49f8144d26a3a5143256e3f65d82f36e53 Mon Sep 17 00:00:00 2001 From: daniel-k Date: Mon, 22 Aug 2016 19:32:08 +0200 Subject: [PATCH] gdb-scripts: add convenience scripts to investigate kernel internals These scripts are based on those from the Linux kernel and currently can only show the state of HermitCore tasks. --- hermit/usr/gdb/README.md | 59 ++++++++++++ hermit/usr/gdb/hermit-gdb.py | 25 +++++ hermit/usr/gdb/hermit/__init__.py | 1 + hermit/usr/gdb/hermit/tasks.py | 149 ++++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 hermit/usr/gdb/README.md create mode 100644 hermit/usr/gdb/hermit-gdb.py create mode 100644 hermit/usr/gdb/hermit/__init__.py create mode 100644 hermit/usr/gdb/hermit/tasks.py diff --git a/hermit/usr/gdb/README.md b/hermit/usr/gdb/README.md new file mode 100644 index 000000000..7f458fa60 --- /dev/null +++ b/hermit/usr/gdb/README.md @@ -0,0 +1,59 @@ +GDB-scripts for HermitCore awareness +==================================== + +The scripts located in this folder can be used when debugging HermitCore +applications to gain more insight into kernel internals. + +To use the scripts you have to load them from inside GDB: + +``` +(gdb) source ../gdb/hermit-gdb.py +``` + +## Examples + +Show state of all tasks: + +``` +(gdb) hermit-ps + ID | STATE | CPU | PRIO | STACK | INSTRUCTION POINTER +-------------------------------------------------------------------- + 0 | IDL | 0 | 0 | 0x87f000 | 0x81108c + 1 | IDL | 1 | 0 | 0x881000 | 0x81108c + 2 | BLK | 0 | 8 | 0xd6000 | 0x81108c + 3 | BLK | 0 | 16 | 0xf8000 | 0x81108c + 4 | RUN | 1 | 8 | 0x10e000 | 0x981ee8 + 5 | RUN | 0 | 8 | 0x124000 | 0x981e98 +``` + +Investigate state of specific task: + +``` +(gdb) print $hermit_task_by_id(2) +$1 = {id = 2, status = 3, last_core = 0, last_stack_pointer = 0x107e60, stack = 0xf8000, ist_addr = 0xe7000, flags = 0 '\000', + prio = 16 '\020', timeout = 883, start_tick = 207, heap = 0x0, parent = 0, next = 0x0, prev = 0x0, tls_addr = 12204928, + tls_size = 24, lwip_err = 0, signal_handler = 0x0, fpu = {fsave = {cwd = 0, swd = 0, twd = 0, fip = 0, fcs = 0, foo = 0, fos = 0, + st_space = {0 }, status = 0}, fxsave = {cwd = 0, swd = 0, twd = 0, fop = 0, {{rip = 0, rdp = 0}, {fip = 0, + fcs = 0, foo = 0, fos = 0}}, mxcsr = 0, mxcsr_mask = 0, st_space = {0 }, xmm_space = { + 0 }, padding = {0 }, {padding1 = {0 }, sw_reserved = { + 0 }}}, xsave = {fxsave = {cwd = 0, swd = 0, twd = 0, fop = 0, {{rip = 0, rdp = 0}, {fip = 0, fcs = 0, + foo = 0, fos = 0}}, mxcsr = 0, mxcsr_mask = 0, st_space = {0 }, xmm_space = {0 }, + padding = {0 }, {padding1 = {0 }, sw_reserved = {0 }}}, hdr = { + xstate_bv = 0, xcomp_bv = 0, reserved = {0, 0, 0, 0, 0, 0}}, ymmh = {ymmh_space = {0 }}}}} +``` + +Show registered signal handlers (by `hermit_signal(signal_handler_t handler)`). +Note that these are not signal handlers registered by newlib +(`signal(int sig, _sig_func_ptr func)`). + +``` +(gdb) hermit-ls-sighandler + ID | Signal Handler +------------------------------ + 0 | 0x0 + 1 | 0x0 + 2 | 0x989660 + 3 | 0x0 + 4 | 0x989660 + 5 | 0x989660 +``` diff --git a/hermit/usr/gdb/hermit-gdb.py b/hermit/usr/gdb/hermit-gdb.py new file mode 100644 index 000000000..390f70a21 --- /dev/null +++ b/hermit/usr/gdb/hermit-gdb.py @@ -0,0 +1,25 @@ +# +# gdb helper commands and functions for Linux kernel debugging +# +# loader module +# +# Copyright (c) Siemens AG, 2012, 2013 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL version 2. +# + +import os + +sys.path.insert(0, os.path.dirname(__file__)) + +try: + gdb.parse_and_eval("0") + gdb.execute("", to_string=True) +except: + gdb.write("NOTE: gdb 7.2 or later required for Linux helper scripts to " + "work.\n") +else: + import hermit.tasks diff --git a/hermit/usr/gdb/hermit/__init__.py b/hermit/usr/gdb/hermit/__init__.py new file mode 100644 index 000000000..4680fb176 --- /dev/null +++ b/hermit/usr/gdb/hermit/__init__.py @@ -0,0 +1 @@ +# nothing to do for the initialization of this package diff --git a/hermit/usr/gdb/hermit/tasks.py b/hermit/usr/gdb/hermit/tasks.py new file mode 100644 index 000000000..c5f8705c3 --- /dev/null +++ b/hermit/usr/gdb/hermit/tasks.py @@ -0,0 +1,149 @@ +# +# gdb helper commands and functions for HermitCore debugging +# +# task & thread tools +# +# Copyright (c) Siemens AG, 2011-2013 +# Copyright (c) RWTH-Aaachen, 2016 +# +# Authors: +# Jan Kiszka +# Daniel Krebs +# +# Inspired by prior work of Jan Kiszka and adapted by Daniel Krebs +# for HermitCore. +# +# This work is licensed under the terms of the GNU GPL version 2. +# + +import gdb + + +def task_lists(): + task_table = gdb.parse_and_eval("task_table") + + for i in range(task_table.type.range()[1]): + task = task_table[i] + if task['status'] != 0: + yield task + +def get_task_by_pid(pid): + for task in task_lists(): + if int(task['id']) == pid: + return task + return None + + +class HermitTaskByIdFunc(gdb.Function): + """Find HermitCore task by ID and return the task_t variable. + +$hermit_task_by_pid(ID): Given ID, iterate over all tasks of the target and +return that task_t variable which PI matches.""" + + def __init__(self): + super(HermitTaskByIdFunc, self).__init__("hermit_task_by_id") + + def invoke(self, pid): + task = get_task_by_pid(pid) + if task: + return task + else: + raise gdb.GdbError("No task with ID " + str(pid)) + + +HermitTaskByIdFunc() + +def addressToSymbol(addr): + s = gdb.execute("info symbol 0x%x" % addr, to_string=True) + if 'No symbol matches' in s: + return '' + else: + return s.split(' in')[0].replace(' ', '') + +class HermitPs(gdb.Command): + """Dump Hermit tasks.""" + + def __init__(self): + super(HermitPs, self).__init__("hermit-ps", gdb.COMMAND_DATA) + + def invoke(self, arg, from_tty): + # see include/hermit/task_types.h + status_desc = {1: 'RDY', 2: 'RUN', 3: 'BLK', 4: 'FIN', 5: 'IDL'} + + rowfmt = "{id:>3} | {status:^5} | {last_core:>3} | {prio:>4} | {stack:>10} | {rip:<28}\n" + + header = rowfmt.format(id='ID', status='STATE', last_core='CPU', + prio='PRIO', stack='STACK', + rip='INSTRUCTION POINTER') + + gdb.write(header) + gdb.write((len(header) - 1) * '-' + '\n') + + inferior = gdb.selected_inferior() + currentInferiorThread = gdb.selected_thread() + + for task in task_lists(): + + task_status = status_desc[int(task["status"])] + + if task_status == 'RUN': + # switch to inferior thread (cpu) that this task is running on + for inferiorThread in inferior.threads(): + # GDB starts indexing at 1 + coreId = inferiorThread.num - 1 + if coreId == task['last_core']: + inferiorThread.switch() + break + + # get instruction pointer and switch back + rip = str(gdb.parse_and_eval('$pc')) + currentInferiorThread.switch() + + else: + # find instruction pointer in saved stack + rip_addr = task['last_stack_pointer'] + 20 + rip_val = int(rip_addr.dereference()) + # try to resolve a symbol + rip_sym = addressToSymbol(rip_val) + rip = "0x%x" % rip_val + if rip_sym: + rip += " <%s>" % rip_sym + + gdb.write(rowfmt.format( + id=int(task["id"]), + status=task_status, + rip=str(rip), + prio=int(task['prio']), + last_core=int(task['last_core']), + stack="{:#x}".format(int(task['stack'])) + )) + +HermitPs() + + +class HermitLsSighandler(gdb.Command): + """List signal handlers per tasks.""" + + def __init__(self): + super(HermitLsSighandler, self).__init__("hermit-ls-sighandler", gdb.COMMAND_DATA) + + def invoke(self, arg, from_tty): + + rowfmt = "{id:>3} | {signal_handler:<24}\n" + + header = rowfmt.format(id='ID', signal_handler='Signal Handler') + + gdb.write(header) + gdb.write((len(header) - 1) * '-' + '\n') + + inferior = gdb.selected_inferior() + currentInferiorThread = gdb.selected_thread() + + for task in task_lists(): + + gdb.write(rowfmt.format( + id=int(task["id"]), + signal_handler=str(task['signal_handler']), + )) + +HermitLsSighandler()