Skip to content

Commit

Permalink
contrib: add helpers to dump call stacks of a mutex owner and waiters.
Browse files Browse the repository at this point in the history
These don't have tets cases so can't go under helpers.
I have put these under contrib so that they are available
for use.

  python3 -m drgn -s vmlinux -c vmcore contrib/locks.py --help

  usage: locks.py [-h] lock_type info_type [locks ...]

  positional arguments:
    lock_type   type of lock i.e mutex. semaphore, rwsemaphore etc.
    info_type   "owner" or "waiter" or "all"
    locks       list of lock addresses

  options:
    -h, --help  show this help message and exit

For example following command will give us call stack for owner
waiters of specified mutex(es):

  python3 -m drgn -s vmlinux -c vmcore contrib/locks.py mutex all ffffffffc0143400
  ..................
  Dumping call stack for waiter of mutex: ffffffffc0143400

  call stack for pid: 215
  #0  context_switch (kernel/sched/core.c:5238:2)
  osandov#1  __schedule (kernel/sched/core.c:6551:8)
  osandov#2  schedule (kernel/sched/core.c:6627:3)
  osandov#3  schedule_preempt_disabled (kernel/sched/core.c:6686:2)
  osandov#4  __mutex_lock_common (kernel/locking/mutex.c:679:3)
  osandov#5  __mutex_lock (kernel/locking/mutex.c:747:9)
  osandov#6  0xffffffffc01411f6
  ..................

  call stack for pid: 216
  #0  context_switch (kernel/sched/core.c:5238:2)
  osandov#1  __schedule (kernel/sched/core.c:6551:8)
  osandov#2  schedule (kernel/sched/core.c:6627:3)
  osandov#3  schedule_preempt_disabled (kernel/sched/core.c:6686:2)
  osandov#4  __mutex_lock_common (kernel/locking/mutex.c:679:3)
  osandov#5  __mutex_lock (kernel/locking/mutex.c:747:9)
  osandov#6  0xffffffffc014112b
  ..................

  Dumping call stack for owner of mutex: ffffffffc0143400

  call stack for pid: 214
  #0  delay_tsc (arch/x86/lib/delay.c:79:3)
  osandov#1  0xffffffffc0141308
  ..................

  Signed-off-by: Imran Khan <[email protected]>
  • Loading branch information
imran-kn committed Mar 16, 2024
1 parent ec6aea2 commit 69cb794
Showing 1 changed file with 78 additions and 0 deletions.
78 changes: 78 additions & 0 deletions contrib/locks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env drgn
# Copyright (c) 2024, Oracle and/or its affiliates.
# SPDX-License-Identifier: LGPL-2.1-or-later

""" Script to dump lock information"""

import sys
from argparse import ArgumentParser
from drgn import Object
from drgn.helpers.linux.locks import mutex_is_locked
from drgn.helpers.linux.locks import mutex_owner
from drgn.helpers.linux.locks import mutex_for_each_waiter_task

###############################################
# mutex
###############################################
def dump_mutex_waiters_call_stack(mutex: Object) -> None:
"""
Dump call stacks for all tasks blocked on a mutex.
:param lock: ``struct mutex *``
"""
prog = mutex.prog_
print(f"Dumping call stack for waiter of mutex: {mutex.value_():x}")
for task in mutex_for_each_waiter_task(mutex):
trace = prog.stack_trace(task.pid.value_())
print(f"\ncall stack for pid: {task.pid.value_()}")
print(trace)
print("\n")


def dump_mutex_owner_call_stack(mutex: Object) -> None:
"""
Dump call stack of mutex owner.
:param lock: ``struct mutex *``
"""
prog = mutex.prog_
if mutex_is_locked(mutex):
owner = mutex_owner(mutex)
print(f"Dumping call stack for owner of mutex: {mutex.value_():x}")
trace = prog.stack_trace(owner.pid.value_())
print(f"\ncall stack for pid: {owner.pid.value_()}")
print(trace)
print("\n")


def parse_cmdline_args(args):
parser = ArgumentParser()
parser.add_argument("lock_type", type=str, help="type of lock i.e mutex. semaphore, rwsemaphore etc.")
parser.add_argument("info_type", type=str, help="\"owner\" or \"waiter\" or \"all\"")
parser.add_argument("locks", nargs="*", default=None, help="list of lock addresses")
args = parser.parse_args()
return args

def main():
cmd_opts = parse_cmdline_args(sys.argv[1:])
lock_type = cmd_opts.lock_type
info_type = cmd_opts.info_type
if isinstance(cmd_opts.locks, list):
locks = cmd_opts.locks

if lock_type == "semaphore" and info_type == "owner":
print ("Owner info not available for semaphores.")

if lock_type == "mutex":
for lock_addr in locks:
lock = Object(prog, "struct mutex", address=int(lock_addr, 16))
if (info_type == "all" or info_type == "waiter"):
dump_mutex_waiters_call_stack(lock.address_of_())
if (info_type == "all" or info_type == "owner"):
dump_mutex_owner_call_stack(lock.address_of_())
else:
print(f"No information available for {lock_type}.")


if __name__ == "__main__":
main()

0 comments on commit 69cb794

Please sign in to comment.