Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

determine the vmlinux file from the crash dump #285

Closed
wants to merge 53 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
0aec3a9
Create a znode command for sdb. Also create znode2inode and
PaulZ-98 Jun 28, 2021
fa9ec7d
Allow sdb to load commands if the walker class cannot find all
tony-zfs Jul 13, 2021
499749d
Merge branch 'bugfix/fix_084_sdb_crash' into 'master'
tony-zfs Aug 12, 2021
cbc21f2
Add zfs_refcount command
PaulZ-98 Sep 22, 2021
36582d4
Add a zio command to sdb
PaulZ-98 Oct 5, 2021
6066a83
Add blkptr command to sdb.
PaulZ-98 Aug 18, 2021
27f0a6e
Add mutex and rrwlock commands to sdb
PaulZ-98 Sep 23, 2021
c05fd47
Add nvlist command to sdb
PaulZ-98 Nov 11, 2021
4ecad1c
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
62e3b4a
Update requirement.txt
PaulZ-98 Nov 23, 2021
4366b64
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
2184844
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
c13a006
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
42a4e75
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
6a3383e
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
03a80b1
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
28b5bc9
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
8ec9fde
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
aad16d8
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
3f0e763
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
0b33548
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
3482866
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
53bebd5
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
1e9395f
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
cfad48f
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
ba2e213
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
408251f
Update sdb/pipeline.py
PaulZ-98 Nov 23, 2021
41194d1
Update sdb/command.py
PaulZ-98 Nov 23, 2021
d5fa139
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
dd85c53
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
514896c
Deleted requirement.txt
PaulZ-98 Nov 23, 2021
ce6a973
Update .gitlab-ci.yml
PaulZ-98 Nov 23, 2021
87b5fdc
Add the ps command to sdb.
tony-zfs Mar 24, 2021
73f4e0e
Merge branch 'ci-test' into 'master'
tony-zfs Jan 13, 2022
517f511
Merge branch 'sdb_refcount' into 'master'
tony-zfs Jan 13, 2022
d103cb6
Fix CI failure, yapf reports formatting error in exit.py
PaulZ-98 Jan 21, 2022
c3ff51a
Merge branch 'ci-fix-format' into 'master'
PaulZ-98 Jan 21, 2022
6f9edc0
Merge branch 'sdb_zio' into 'master'
tony-zfs Jan 26, 2022
99ff716
Merge branch 'sdb_mutex' into 'master'
tony-zfs Jan 26, 2022
b42f525
Merge branch 'sdb_nvlist' into 'master'
tony-zfs Jan 26, 2022
7924e6d
Merge branch 'sdb_blkptr' into 'master'
tony-zfs Jan 26, 2022
84d6df5
Merge branch 'master' into 'sdb_znode'
tony-zfs Jan 26, 2022
07ad3f0
Update sdb/commands/zfs/znode.py
tony-zfs Jan 26, 2022
da051d7
Fix issues with paul during cicd process.
tony-zfs Jan 26, 2022
360a96d
Merge branch 'sdb_znode' into 'master'
tony-zfs Jan 26, 2022
8008252
Merge branch 'add_ps_support' into 'master'
tony-zfs Jan 26, 2022
37627d4
Fixes to pass tests
PaulZ-98 Jan 27, 2022
db19454
Merge branch 'sdb_testfix' into 'master'
PaulZ-98 Jan 27, 2022
a4c644e
Enhance the sdb print command to allow a new parameter "-S"
tony-zfs Feb 17, 2022
02ec4c5
Merge branch 'feature/enhance_print_cmd' into 'master'
tony-zfs Feb 17, 2022
7d0594f
Handle exception when gathering stacks
Feb 18, 2022
4ef6bed
Merge branch 'sdb_stacksfix' into 'master'
tony-zfs Feb 18, 2022
6f7dc00
sdb should detect vmlinux version from crash dump
PaulZ-98 Mar 16, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#
# Code quality checking for sdb
#
image: "python:3.8"

before_script:
- python --version
- python3 -m pip install pylint==2.6
- python3 -m pip install yapf
- python3 -m pip install mypy==0.730
- pip3 install drgn

job:
tags:
- use1-ci-builder-20
script:
- pylint -d duplicate-code -d invalid-name sdb
- yapf --diff --style google --recursive sdb
- python3 -m mypy --strict --show-error-codes -p sdb
11 changes: 7 additions & 4 deletions sdb/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,10 +597,13 @@ def _help_message(input_type: drgn.Type = None) -> str:
return msg

def _call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]:
baked = {
type_canonicalize_name(type_): class_
for type_, class_ in Walker.allWalkers.items()
}
baked = dict()
for type_, class_ in Walker.allWalkers.items():
try:
baked[type_canonicalize_name(type_)] = class_
except LookupError:
pass

has_input = False
for i in objs:
has_input = True
Expand Down
1 change: 0 additions & 1 deletion sdb/commands/exit.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@


class Exit(sdb.Command):

"Exit the application"

names = ["exit", "quit"]
Expand Down
110 changes: 110 additions & 0 deletions sdb/commands/linux/mutex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#
# Copyright 2019 Delphix
# Copyright 2021 Datto, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# pylint: disable=missing-docstring

import drgn
from drgn.helpers.linux.list import list_for_each
import sdb
from sdb.commands.linux.process import Process


class Mutex(sdb.PrettyPrinter):
"""
DESCRIPTION

Display the owner of a mutex and its waiters.

EXAMPLES (some output shortened)

sdb> spa |member spa_activities_lock | member m_mutex | mutex
owner of mutex 0xffff925f36005eb8:
--------------------------------
PID: 13205 zpool scrub tank

#0 at 0xffffffff90d79914 (__schedule+0x394/0xa53) in context_switch at ../core.c:3551:2
#1 at 0xffffffff90d79914 (__schedule+0x394/0xa53) in __schedule at ../core.c:4312:8
#2 at 0xffffffff90d7a035 (schedule+0x55/0xba) in schedule at ../kernel/sched/core.c:4387:3
#3 at 0xffffffff90d7a406 (io_schedule+0x16/0x3a) in io_schedule at ../kernel/sched/core.c:6029:2
#4 at 0xffffffffc09246ff (cv_wait_common+0xef/0x297) in cv_wait_common at ../spl-condvar.c:144:3
#5 at 0xffffffffc09248e8 (__cv_wait_io+0x18/0x1a) in __cv_wait_io at ../spl/spl-condvar.c:178:2
#6 at 0xffffffffc0be06b3 (txg_wait_synced_impl+0xf3/0x258) in txg_wait_synced_impl at ..
#7 at 0xffffffffc0be0830 (txg_wait_synced+0x10/0x3b) in txg_wait_synced at ../txg.c:736:2
#8 at 0xffffffffc0b93d72 (dsl_sync_task_common+0x1c2/0x296) in dsl_sync_task_common at ..
#9 at 0xffffffffc0b93e6a (dsl_sync_task+0x1a/0x1c) in dsl_sync_task at ../dsl_synctask.c:132:10
#10 at 0xffffffffc0b91206 (dsl_scan+0x96/0x123) in dsl_scan at ../dsl_scan.c:853:10
#11 at 0xffffffffc0bbeaf1 (spa_scan+0x81/0x1c0) in spa_scan at ../spa.c:8037:10
#12 at 0xffffffffc0c37a80 (zfs_ioc_pool_scan+0x60/0xd1) in zfs_ioc_pool_scan at zfs_ioctl.c:1691
#13 at 0xffffffffc0c413b9 (zfsdev_ioctl_common+0x609/0x6b7) in zfsdev_ioctl_common at ..
#14 at 0xffffffffc0c7c477 (zfsdev_ioctl+0x57/0xdf) in zfsdev_ioctl at ../zfs/module/zfs/..
#15 at 0xffffffff9050349d (ksys_ioctl+0x9d/0xc2) in vfs_ioctl at ../fs/ioctl.c:48:10 (inlined)
#16 at 0xffffffff9050349d (ksys_ioctl+0x9d/0xc2) in ksys_ioctl at ../fs/ioctl.c:753:11
#17 at 0xffffffff905034ea (__x64_sys_ioctl+0x1a/0x1e) in __do_sys_ioctl at ../fs/ioctl.c:762:9
#18 at 0xffffffff905034ea (__x64_sys_ioctl+0x1a/0x1e) in __se_sys_ioctl at ../fs/ioctl.c:760:1
#19 at 0xffffffff905034ea (__x64_sys_ioctl+0x1a/0x1e) in __x64_sys_ioctl at ../fs/ioctl.c:760:1
#20 at 0xffffffff90d6cb89 (do_syscall_64+0x49/0xb6) in do_syscall_64 at ..
#21 at 0xffffffff90e0008c (entry_SYSCALL_64+0x7c/0x156) at ../arch/x86/entry/entry_64.S:117
--------------------------------


waiters on mutex 0xffff925f36005eb8:
--------------------------------
PID: 13156

#0 at 0xffffffff90d79914 (__schedule+0x394/0xa53) in context_switch at ../core.c:3551
#1 at 0xffffffff90d79914 (__schedule+0x394/0xa53) in __schedule at ../core.c:4312:8
#2 at 0xffffffff90d7a035 (schedule+0x55/0xba) in schedule at ../core.c:4387:3
#3 at 0xffffffff90d7a33e (schedule_preempt_disabled+0xe/0x10) in schedule_preempt_disabled at ..
#4 at 0xffffffff90d7bf1d (__mutex_lock.isra.0+0x17d/0x4e0) in __mutex_lock_common at ..
#5 at 0xffffffff90d7bf1d (__mutex_lock.isra.0+0x17d/0x4e0) in __mutex_lock at ..
#6 at 0xffffffff90d7c293 (__mutex_lock_slowpath+0x13/0x15) in __mutex_lock_slowpath at ..
#7 at 0xffffffff90d7c2d2 (mutex_lock+0x32/0x36) in mutex_lock at ../kernel/locking/mutex.c:284:3
#8 at 0xffffffffc0bc5a35 (spa_notify_waiters+0x35/0x9b) in spa_notify_waiters at ../spa.c:9546:2
#9 at 0xffffffffc0b8ce8b (dsl_process_async_destroys+0x21b/0x73a) in dsl_process_async_destroys
#10 at 0xffffffffc0b92e63 (dsl_scan_sync+0x1e3/0xb70) in dsl_scan_sync at ../dsl_scan.c:3571:8
#11 at 0xffffffffc0bc040a (spa_sync_iterate_to_convergence+0x13a/0x317) in spa_sync_iterate..
#12 at 0xffffffffc0bc0bc2 (spa_sync+0x2f2/0x872) in spa_sync at ../zfs/module/zfs/spa.c:9269:2
#13 at 0xffffffffc0be14d7 (txg_sync_thread+0x2a7/0x3de) in txg_sync_thread at ../txg.c:591:3
#14 at 0xffffffffc092ec94 (thread_generic_wrapper+0x84/0xbc) in thread_generic_wrapper at ..
#15 at 0xffffffff902c18f4 (kthread+0x114/0x146) in kthread at ../kernel/kthread.c:291:9
#16 at 0xffffffff90204482 (ret_from_fork+0x22/0x2d) at ../arch/x86/entry/entry_64.S:293
--------------------------------

"""

names = ["mutex"]
input_type = "struct mutex *"
output_type = "struct mutex *"
MUTEX_FLAGS = 0x07

def pretty_print(self, objs: drgn.Object) -> None:
for mtx in objs:
# see __mutex_owner() in kernel/locking/mutex.c
print(f"owner of mutex {hex(int(mtx))}:")
if mtx.owner.counter != 0:
contents = sdb.get_prog().read_u64(mtx.owner.address_of_())
own_addr = int(contents) & ~self.MUTEX_FLAGS
own_task = sdb.create_object('struct task_struct *', own_addr)
Process(own_task.pid).print_process()
else:
print("NULL")

# waiters
print(f"waiters on mutex {hex(int(mtx))}:")
for obj in list_for_each(mtx.wait_list.address_of_()):
sw = drgn.cast('struct semaphore_waiter *', obj)
Process(sw.task.pid).print_process()
32 changes: 32 additions & 0 deletions sdb/commands/linux/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,41 @@
from typing import Iterable

import drgn
from drgn.helpers.linux.pid import find_task, for_each_pid
from drgn.helpers.linux.mm import cmdline
import sdb


class Process:

def __init__(self, pid: int = 0) -> None:
self.pid = pid
self.prog = sdb.get_prog()

# yield all the pid_t in the process table
def all(self) -> Iterable[drgn.Object]:
for pid in for_each_pid(self.prog):
yield pid

def print_process(self, indent: int = 0) -> None:
# handle exception when no cmd line is present
try:
cmd = cmdline(find_task(sdb.get_prog(), self.pid))
except drgn.FaultError:
cmd = []
print("--------------------------------")
print(f"PID: {int(self.pid)} ", end='')
for c in cmd:
c_str = c.decode("utf-8")
print(f"{c_str} ", end='')
print("\n")
trace = sdb.get_prog().stack_trace(self.pid)
for frame in trace:
print(f"{' '*indent}{frame}")
print("--------------------------------")
print("\n")


class FindPid(sdb.Command):
"""
Return "struct pid *" for the given PID number in the global namespace.
Expand Down
156 changes: 156 additions & 0 deletions sdb/commands/linux/ps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#
# Copyright 2021 Datto Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# pylint: disable=missing-docstring

import datetime
import argparse
from typing import Callable, Dict, Iterable, List, Union

import drgn
from drgn.helpers.linux.pid import for_each_task

import sdb
from sdb.commands.stacks import Stacks
from sdb.commands.threads import Threads


class Ps(Threads):
"""
Locate and print information about processes

POTENTIAL COLUMNS
task - address of the task_struct
uid - user id
pid - the pid of the thread's process
time - cumulative CPU time, "[DD-]HH:MM:SS" format
state - the state of the thread
prio - the priority of the thread
comm - the thread's command
cmdline - the thread's command line (when available)

EXAMPLE
sdb> ps -e
task uid pid time stime ppid cmd
------------------ ---- ---- ------- ------- ----- ----------------
0xffff9995001a0000 1000 4387 0:00:00 0:00:00 1218 inotify_reader
0xffff9995001a2d00 1000 4382 0:00:00 0:00:00 1218 slack
0xffff9995001a4380 1000 4383 0:00:04 0:00:00 1218 slack
0xffff9995001a5a00 1000 4554 0:11:00 0:09:56 4118 AudioIP~ent RPC
0xffff99950a430000 1000 4284 0:00:00 0:00:00 4118 HTML5 Parser
0xffff99950a431680 1000 4157 0:00:12 0:00:08 1218 localStorage DBa
...
"""

names = ["ps"]
input_type = "struct task_struct *"
output_type = "struct task_struct *"

FIELDS: Dict[str, Callable[[drgn.Object], Union[str, int]]] = {
"task":
lambda obj: hex(obj.value_()),
"uid":
lambda obj: int(
sdb.create_object("struct cred *", obj.real_cred).uid.val),
"pid":
lambda obj: int(obj.pid),
"time":
lambda obj: str(
datetime.timedelta(seconds=int(obj.utime) / 1000 / 1000)),
"stime":
lambda obj: str(
datetime.timedelta(seconds=int(obj.stime) / 1000 / 1000)),
"ppid":
lambda obj: int(obj.parent.pid),
"stat":
lambda obj: str(Stacks.task_struct_get_state(obj)),
"cmd":
lambda obj: str(obj.comm.string_().decode("utf-8")),
}

@classmethod
def _init_parser(cls, name: str) -> argparse.ArgumentParser:
parser = super()._init_parser(name)
parser.add_argument('-e', '--every', action='store_true', \
help="Select all processes. Identical to -A")
parser.add_argument('-A', '--all', action='store_true', \
help="Select all processes. Identical to -e")
parser.add_argument('-C', '--C', type=str, \
help="Print only the process IDs of a command")
parser.add_argument('-x', '--x', action='store_true', \
help="Show PID, TIME, CMD")
parser.add_argument('--no-headers', '--no-heading', \
action='store_true', \
help="Show the output without headers.")
parser.add_argument('-p', '--pid', type=int, nargs="+", \
help="Select by process ID. Identical to --pid.")
parser.add_argument('-P', '--ppid', type=int, nargs="+", \
help="Select by parent process ID. \
This selects the processes with \
a parent process ID in the pid list."
)
parser.add_argument('-o',
'--format',
type=str,
help="User-defined format. \
format is a single argument in the form of a blank-separated \
or comma-separated list, which offers a way to specify individual\
output columns. Headers may be renamed (ps -o pid,ppid) as desired. "
)
return parser

def get_table_key(self) -> str:
return "pid"

def get_filtered_fields(self) -> List[str]:
fields = list(self.FIELDS.keys())
fields_option_ae = [
x for x in fields if x in "task, uid, pid, ppid, stime, time, cmd"
]
fields_option_x = [x for x in fields if x in "pid, stat, time, cmd"]
fields_option_default = [x for x in fields if x in "pid, time, cmd"]

if self.args.every or self.args.all:
fields = fields_option_ae
elif self.args.x:
fields = fields_option_x
elif self.args.format:
fields_option_o = 'task,' + self.args.format.lower()
fields_option_o = [x for x in fields if x in fields_option_o]
fields = fields_option_o
else:
fields = fields_option_default
return fields

def show_headers(self) -> bool:
return not self.args.no_headers

def no_input(self) -> Iterable[drgn.Object]:
cmds = self.args.C.split(",") if self.args.C else []
pids = self.args.pid if self.args.pid else []
ppids = self.args.ppid if self.args.ppid else []
for obj in for_each_task(sdb.get_prog()):
if self.args.pid:
if obj.pid not in pids:
continue
if self.args.C:
cmd = str(obj.comm.string_().decode("utf-8"))
if cmd not in cmds:
continue
if self.args.ppid:
if obj.parent.pid not in ppids:
continue
yield obj
26 changes: 26 additions & 0 deletions sdb/commands/nvpair/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#
# Copyright 2019 Delphix
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# pylint: disable=missing-docstring

import glob
import importlib
import os

for path in glob.glob("{}/*.py".format(os.path.dirname(__file__))):
if path != __file__:
module = os.path.splitext(os.path.basename(path))[0]
importlib.import_module("sdb.commands.nvpair.{}".format(module))
Loading