1
0
Fork 0
mirror of https://github.com/hermitcore/libhermit.git synced 2025-03-09 00:00:03 +01:00

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.
This commit is contained in:
daniel-k 2016-08-22 19:32:08 +02:00
parent 5e9f932869
commit d46b8b49f8
4 changed files with 234 additions and 0 deletions

59
hermit/usr/gdb/README.md Normal file
View file

@ -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 <rollback>
1 | IDL | 1 | 0 | 0x881000 | 0x81108c <rollback>
2 | BLK | 0 | 8 | 0xd6000 | 0x81108c <rollback>
3 | BLK | 0 | 16 | 0xf8000 | 0x81108c <rollback>
4 | RUN | 1 | 8 | 0x10e000 | 0x981ee8 <thread_func1+40>
5 | RUN | 0 | 8 | 0x124000 | 0x981e98 <thread_func2+40>
```
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 <repeats 20 times>}, 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 <repeats 32 times>}, xmm_space = {
0 <repeats 64 times>}, padding = {0 <repeats 12 times>}, {padding1 = {0 <repeats 12 times>}, sw_reserved = {
0 <repeats 12 times>}}}, 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 <repeats 32 times>}, xmm_space = {0 <repeats 64 times>},
padding = {0 <repeats 12 times>}, {padding1 = {0 <repeats 12 times>}, sw_reserved = {0 <repeats 12 times>}}}, hdr = {
xstate_bv = 0, xcomp_bv = 0, reserved = {0, 0, 0, 0, 0, 0}}, ymmh = {ymmh_space = {0 <repeats 64 times>}}}}}
```
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 <signal_dispatcher>
3 | 0x0
4 | 0x989660 <signal_dispatcher>
5 | 0x989660 <signal_dispatcher>
```

View file

@ -0,0 +1,25 @@
#
# gdb helper commands and functions for Linux kernel debugging
#
# loader module
#
# Copyright (c) Siemens AG, 2012, 2013
#
# Authors:
# Jan Kiszka <jan.kiszka@siemens.com>
#
# 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

View file

@ -0,0 +1 @@
# nothing to do for the initialization of this package

View file

@ -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 <jan.kiszka@siemens.com>
# Daniel Krebs <github@daniel-krebs.net>
#
# 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()