Skip to content

Commit b4d55fd

Browse files
authored
Merge pull request #273 from delphix/master
Merge branch 'master' into '6.0/stage'
2 parents 24ba22f + 39ec94f commit b4d55fd

File tree

9 files changed

+134
-3
lines changed

9 files changed

+134
-3
lines changed

README.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# sdb
2-
The Slick/Simple Debugger
2+
The Slick Debugger
33

44
![](https://github.com/delphix/sdb/workflows/.github/workflows/main.yml/badge.svg)
55

@@ -21,6 +21,35 @@ $ sudo python3 setup.py install
2121

2222
The above should install `sdb` under `/usr/local/bin/`.
2323

24+
### Quickstart
25+
26+
Running `sudo sdb` attaches sdb to the running kernel by default.
27+
To debug a running program, run `sudo sdb -p <PID>`.
28+
For post-mortem debugging (either a kernel crash dump or a userland core dump), use `sudo sdb <vmlinux path|userland binary path> <dump>`.
29+
30+
```
31+
$ sudo sdb
32+
sdb> find_task 1 | member comm
33+
(char [16])"systemd"
34+
sdb> find_task 1 | stack
35+
TASK_STRUCT STATE COUNT
36+
==========================================
37+
0xffff89cea441dd00 INTERRUPTIBLE 1
38+
__schedule+0x2e5
39+
schedule+0x33
40+
schedule_hrtimeout_range_clock+0xfd
41+
schedule_hrtimeout_range+0x13
42+
ep_poll+0x40a
43+
do_epoll_wait+0xb7
44+
__x64_sys_epoll_wait+0x1e
45+
do_syscall_64+0x57
46+
entry_SYSCALL_64+0x7c
47+
sdb> addr modules | lxlist "struct module" list | member name ! sort | head -n 3
48+
(char [56])"aesni_intel"
49+
(char [56])"async_memcpy"
50+
(char [56])"async_pq"
51+
```
52+
2453
### Resources
2554

2655
User and developer resources for sdb can be found in the [project's wiki](https://github.com/delphix/sdb/wiki).

sdb/commands/linux/internal/slub_helpers.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616

1717
# pylint: disable=missing-docstring
1818

19-
from typing import Iterable, Set
19+
from typing import Iterable, Set, Optional
2020

2121
import drgn
2222
from drgn.helpers.linux.list import list_for_each_entry
23-
from drgn.helpers.linux.mm import for_each_page, page_to_virt
23+
from drgn.helpers.linux.mm import for_each_page, page_to_virt, virt_to_pfn, pfn_to_page
2424

2525
import sdb
2626

@@ -136,6 +136,18 @@ def cache_red_left_padding(cache: drgn.Object) -> int:
136136
return padding
137137

138138

139+
def lookup_cache_by_address(obj: drgn.Object) -> Optional[drgn.Object]:
140+
pfn = virt_to_pfn(sdb.get_prog(), obj)
141+
page = pfn_to_page(pfn)
142+
cache = page.slab_cache
143+
try:
144+
# read the name to force FaultError if any
145+
_ = cache.name.string_().decode('utf-8')
146+
except drgn.FaultError:
147+
return None
148+
return cache
149+
150+
139151
def cache_get_free_pointer(cache: drgn.Object, p: drgn.Object) -> drgn.Object:
140152
"""
141153
Get the next pointer in the freelist. Note, that this

sdb/commands/linux/whatis.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#
2+
# Copyright 2020 Delphix
3+
# Copyright 2021 Datto Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
# pylint: disable=missing-docstring
19+
20+
import argparse
21+
from typing import Iterable
22+
23+
import drgn
24+
import sdb
25+
from sdb.commands.linux.internal import slub_helpers as slub
26+
27+
28+
class WhatIs(sdb.Command):
29+
"""
30+
Print the name of the kmem cache from which the address is allocated.
31+
32+
DESCRIPTION
33+
The address can be specified as an argument, or
34+
passed through a pipe.
35+
36+
EXAMPLES
37+
Determine the kmem_cache for a given address:
38+
39+
sdb> whatis 0xfffffe06596e21b8
40+
0xfffffe06596e21b8 is allocated from dmu_buf_impl_t
41+
42+
Determine the kmem_cache of address passed through a
43+
pipe:
44+
45+
sdb> dbuf |head 1 |deref |member db_buf |whatis
46+
0xffff8e804368ac80 is allocated from arc_buf_t
47+
"""
48+
49+
names = ["whatis"]
50+
51+
@staticmethod
52+
def print_cache(cache: drgn.Object, addr: str) -> None:
53+
if cache is None:
54+
print(f"{addr} does not map to a kmem_cache")
55+
else:
56+
assert sdb.type_canonical_name(cache.type_) == 'struct kmem_cache *'
57+
cache_nm = cache.name.string_().decode('utf-8')
58+
print(f"{addr} is allocated from {cache_nm}")
59+
60+
@classmethod
61+
def _init_parser(cls, name: str) -> argparse.ArgumentParser:
62+
parser = super()._init_parser(name)
63+
parser.add_argument("address", nargs="*", metavar="<address>")
64+
return parser
65+
66+
def _call(self, objs: Iterable[drgn.Object]) -> None:
67+
for obj in objs:
68+
cache = slub.lookup_cache_by_address(obj)
69+
self.print_cache(cache, hex(int(obj)))
70+
for addr in self.args.address:
71+
try:
72+
obj = sdb.create_object("void *", int(addr, 16))
73+
except ValueError:
74+
print(f"{addr} is not a valid address")
75+
continue
76+
cache = slub.lookup_cache_by_address(obj)
77+
self.print_cache(cache, addr)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0xffffa08943a90050 is allocated from arc_buf_t
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0xf987kkbbh is not a valid address
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0xffff does not map to a kmem_cache
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
0xffffa0888c766000 is allocated from arc_buf_hdr_t_full
2+
0xffffa089407ca870 is allocated from dmu_buf_impl_t
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0xffffa089407ca870 is allocated from dmu_buf_impl_t

tests/integration/test_linux_generic.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@
9494
"threads | count",
9595
'threads | filter \'obj.comm == "java"\' | threads',
9696
"thread",
97+
98+
# whatis
99+
"dbuf |head 1 |deref |member db_buf |whatis",
100+
"whatis 0xffffa089407ca870",
101+
"whatis 0xffffa0888c766000 0xffffa089407ca870",
102+
"whatis 0xffff",
103+
"whatis 0xf987kkbbh"
97104
]
98105

99106
STRIPPED_POS_CMDS = [

0 commit comments

Comments
 (0)