mirror of
https://github.com/hermitcore/libhermit.git
synced 2025-03-09 00:00:03 +01:00
Merge pull request #34 from daniel-k/pr/gdb_task_backtrace
gdb-scripts: backtrace and context switching for tasks
This commit is contained in:
commit
2c8a1a3a45
2 changed files with 211 additions and 3 deletions
|
@ -57,3 +57,53 @@ Note that these are not signal handlers registered by newlib
|
|||
4 | 0x989660 <signal_dispatcher>
|
||||
5 | 0x989660 <signal_dispatcher>
|
||||
```
|
||||
|
||||
Show backtrace of suspended (or any) task:
|
||||
|
||||
```
|
||||
(gdb) hermit-ps
|
||||
ID | STATE | CPU | PRIO | STACK | INSTRUCTION POINTER
|
||||
--------------------------------------------------------------------
|
||||
0 | IDL | 0 | 0 | 0x88d000 | 0x80a756 <reschedule+41>
|
||||
1 | IDL | 1 | 0 | 0x88f000 | 0x80a756 <reschedule+41>
|
||||
2 | IDL | 2 | 0 | 0x891000 | 0x80a756 <reschedule+41>
|
||||
3 | IDL | 3 | 0 | 0x893000 | 0x80a756 <reschedule+41>
|
||||
4 | BLK | 0 | 8 | 0xde000 | 0x80a756 <reschedule+41>
|
||||
5 | BLK | 0 | 16 | 0xf8000 | 0x80a756 <reschedule+41>
|
||||
6 | RUN | 1 | 8 | 0x115000 | 0x990070 <thread_func+64>
|
||||
7 | RUN | 2 | 8 | 0x12b000 | 0x990070 <thread_func+64>
|
||||
8 | RUN | 3 | 8 | 0x141000 | 0x990070 <thread_func+64>
|
||||
9 | RUN | 0 | 8 | 0x157000 | 0x990070 <thread_func+64>
|
||||
(gdb) hermit-bt 4
|
||||
#0 0x000000000081701c in rollback ()
|
||||
#1 0x000000000080a756 in reschedule () at kernel/tasks.c:909
|
||||
#2 0x0000000000813f7b in timer_wait (ticks=50) at arch/x86/kernel/timer.c:139
|
||||
#3 0x000000000080b9f7 in sys_msleep (ms=500) at kernel/syscall.c:357
|
||||
#4 0x000000000098fd5e in main ()
|
||||
```
|
||||
|
||||
Switch current context to any task to investigate call stack. Remember to
|
||||
restore the context if you want to continue execution.
|
||||
|
||||
```
|
||||
(gdb) info threads
|
||||
Id Target Id Frame
|
||||
* 1 Thread 1 (CPU#0 [running]) 0x0000000000990070 in thread_func ()
|
||||
2 Thread 2 (CPU#1 [running]) 0x0000000000990070 in thread_func ()
|
||||
3 Thread 3 (CPU#2 [running]) 0x0000000000990070 in thread_func ()
|
||||
4 Thread 4 (CPU#3 [running]) 0x0000000000990070 in thread_func ()
|
||||
(gdb) hermit-switch-context 4
|
||||
(gdb) info threads
|
||||
Id Target Id Frame
|
||||
* 1 Thread 1 (CPU#0 [running]) 0x000000000081701c in rollback ()
|
||||
2 Thread 2 (CPU#1 [running]) 0x0000000000990070 in thread_func ()
|
||||
3 Thread 3 (CPU#2 [running]) 0x0000000000990070 in thread_func ()
|
||||
4 Thread 4 (CPU#3 [running]) 0x0000000000990070 in thread_func ()
|
||||
(gdb) bt
|
||||
#0 0x000000000081701c in rollback ()
|
||||
#1 0x000000000080a756 in reschedule () at kernel/tasks.c:909
|
||||
#2 0x0000000000813f7b in timer_wait (ticks=50) at arch/x86/kernel/timer.c:139
|
||||
#3 0x000000000080b9f7 in sys_msleep (ms=500) at kernel/syscall.c:357
|
||||
#4 0x000000000098fd5e in main ()
|
||||
(gdb) hermit-restore-context
|
||||
```
|
||||
|
|
|
@ -136,9 +136,6 @@ class HermitLsSighandler(gdb.Command):
|
|||
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(
|
||||
|
@ -147,3 +144,164 @@ class HermitLsSighandler(gdb.Command):
|
|||
))
|
||||
|
||||
HermitLsSighandler()
|
||||
|
||||
|
||||
|
||||
def stripSymbol(value):
|
||||
s = "%s" % value
|
||||
return s.split(' ')[0]
|
||||
|
||||
class HermitTaskState:
|
||||
def __init__(self, address = None):
|
||||
import re
|
||||
self.info_reg_regex = re.compile("(?P<register>[\w]+)\s+(?P<value>0x[0-9a-f]+).*")
|
||||
|
||||
if address:
|
||||
self.address = address
|
||||
|
||||
self.registers = {
|
||||
'gs': self.address + 0,
|
||||
'fs': self.address + 1,
|
||||
'r15': self.address + 2,
|
||||
'r14': self.address + 3,
|
||||
'r13': self.address + 4,
|
||||
'r12': self.address + 5,
|
||||
'r11': self.address + 6,
|
||||
'r10': self.address + 7,
|
||||
'r9': self.address + 8,
|
||||
'r8': self.address + 9,
|
||||
'rdi': self.address + 10,
|
||||
'rsi': self.address + 11,
|
||||
'rbp': self.address + 12,
|
||||
'rsp': self.address + 13,
|
||||
'rbx': self.address + 14,
|
||||
'rdx': self.address + 15,
|
||||
'rcx': self.address + 16,
|
||||
'rax': self.address + 17,
|
||||
# int_no
|
||||
# error
|
||||
'rip': self.address + 20,
|
||||
'cs': self.address + 21,
|
||||
'eflags': self.address + 22,
|
||||
# userrsp
|
||||
'ss': self.address + 24,
|
||||
}
|
||||
|
||||
# make nice strings out of register values
|
||||
for register, valptr in self.registers.items():
|
||||
self.registers[register] = stripSymbol(valptr.dereference())
|
||||
|
||||
else:
|
||||
self.address = False
|
||||
self.info_registers = gdb.execute('info registers', to_string=True)
|
||||
self.registers = {}
|
||||
for line in self.info_registers.split('\n'):
|
||||
match = self.info_reg_regex.match(line)
|
||||
if match:
|
||||
self.registers[match.group('register')] = match.group('value')
|
||||
|
||||
def switch(self):
|
||||
for register, value in self.registers.items():
|
||||
try:
|
||||
gdb.execute("set $%s = %s" % (register, value))
|
||||
except:
|
||||
print("Cannot restore %s=%s, skipping ..." % (register, value))
|
||||
|
||||
|
||||
class HermitTaskBacktrace(gdb.Command):
|
||||
"""Show backtrace for HermitCore task.
|
||||
|
||||
Usage: hermit-bt ID"""
|
||||
|
||||
def __init__(self):
|
||||
super(HermitTaskBacktrace, self).__init__("hermit-bt", gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
argv = gdb.string_to_argv(arg)
|
||||
if len(argv) != 1:
|
||||
raise gdb.GdbError("hermit-bt takes one argument")
|
||||
|
||||
task = get_task_by_pid(int(argv[0]))
|
||||
|
||||
if task['status'] == 2:
|
||||
gdb.execute('bt')
|
||||
return
|
||||
|
||||
current_state = HermitTaskState()
|
||||
|
||||
task_state = HermitTaskState(task['last_stack_pointer'])
|
||||
|
||||
try:
|
||||
task_state.switch()
|
||||
gdb.execute('bt')
|
||||
finally:
|
||||
current_state.switch()
|
||||
|
||||
HermitTaskBacktrace()
|
||||
|
||||
original_state = {}
|
||||
|
||||
def saveCurrentState(state):
|
||||
curr_thread = gdb.selected_thread()
|
||||
for thread in gdb.selected_inferior().threads():
|
||||
if not thread.num in state:
|
||||
thread.switch()
|
||||
state[thread.num] = HermitTaskState()
|
||||
curr_thread.switch()
|
||||
|
||||
def restoreCurrentState(state):
|
||||
curr_thread = gdb.selected_thread()
|
||||
for thread in gdb.selected_inferior().threads():
|
||||
if thread.num in state:
|
||||
thread.switch()
|
||||
state[thread.num].switch()
|
||||
curr_thread.switch()
|
||||
state = {}
|
||||
|
||||
class HermitSwitchContext(gdb.Command):
|
||||
"""Switch current context to given HermitCore task
|
||||
|
||||
Usage: hermit-switch-context ID"""
|
||||
|
||||
def __init__(self):
|
||||
super(HermitSwitchContext, self).__init__("hermit-switch-context", gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
global original_state
|
||||
|
||||
argv = gdb.string_to_argv(arg)
|
||||
if len(argv) != 1:
|
||||
raise gdb.GdbError("hermit-switch-context takes one argument")
|
||||
|
||||
# save original state to go back to it later
|
||||
saveCurrentState(original_state)
|
||||
|
||||
task = get_task_by_pid(int(argv[0]))
|
||||
|
||||
# switch current inferior thread to where task has run last
|
||||
for thread in gdb.selected_inferior().threads():
|
||||
if (thread.num - 1) == task['last_core']:
|
||||
thread.switch()
|
||||
break
|
||||
|
||||
# apply it's state
|
||||
task_state = HermitTaskState(task['last_stack_pointer'])
|
||||
task_state.switch()
|
||||
|
||||
HermitSwitchContext()
|
||||
|
||||
|
||||
class HermitRestoreContext(gdb.Command):
|
||||
"""Restore context to state before it was switched
|
||||
|
||||
Usage: hermit-restore-context"""
|
||||
|
||||
def __init__(self):
|
||||
super(HermitRestoreContext, self).__init__("hermit-restore-context", gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
global original_state
|
||||
|
||||
restoreCurrentState(original_state)
|
||||
|
||||
HermitRestoreContext()
|
||||
|
|
Loading…
Add table
Reference in a new issue