Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
f29e1de
crash.types.task: improve task flag handling
jeffmahoney Apr 29, 2019
86422cb
crash.commands.ps: add support for TASK_IDLE
jeffmahoney Apr 29, 2019
68f6630
crash.commands.help: sort commands in help output
jeffmahoney Sep 19, 2018
4fb4c3a
crash.util: add struct_has_member
jeffmahoney Apr 29, 2019
7fe8aa7
crash.types.task: handle anonymous sub-structure in mm_struct
jeffmahoney Apr 29, 2019
b8de0ab
crash.util: add uuid decoding
jeffmahoney May 1, 2019
e75bc23
crash.util: add decode_flags helper
jeffmahoney Apr 26, 2019
81cb971
crash.types.{,k}list: use the type from the symbol when available
jeffmahoney Sep 19, 2018
736fdf7
crash.types.list: add list_empty
jeffmahoney Apr 26, 2019
df92870
crash.types.list: fix cycle tests
jeffmahoney Apr 22, 2019
87aec81
tests: clear file during test teardown
jeffmahoney Apr 22, 2019
ff7ef81
crash.kernel: convert setup to use DelayedSymvals
jeffmahoney Apr 22, 2019
a132e76
crash.arch: add baseline ppc64 support
jeffmahoney Apr 22, 2019
bbe3d6f
crash.types.bitmap: add find first/last/next helpers
jeffmahoney Apr 22, 2019
527e044
crash: use new gdb.Target to create standalone target
jeffmahoney Apr 22, 2019
afdd5b2
crash.types.module: create module for modules
jeffmahoney May 7, 2019
96be843
kdump.target: don't specify offset for .data..percpu
jeffmahoney May 1, 2019
fa71477
crash.types.percpu: handle missing pcpu_nr_slots
jeffmahoney May 6, 2019
c6ec4bc
crash.types.percpu: get_percpu_var, raise exception with passed val
jeffmahoney May 1, 2019
7502b34
crash.types.cpu: fix online cpu mask and add possible cpu mask
jeffmahoney May 7, 2019
36a58b8
crash.types.percpu: better percpu handling
jeffmahoney Apr 22, 2019
118bbfe
crash.types.percpu: separate the all-cpus and single-cpu cases
jeffmahoney May 21, 2019
7b38ed4
crash.types.percpu: add percpu_counter_sum
jeffmahoney Apr 30, 2019
a515eef
crash: auto-select crashing task and print backtrace on startup
jeffmahoney Apr 22, 2019
f6feb54
crash.sh: use $TMPDIR for gdbinit in --gdb mode
jeffmahoney May 1, 2019
fe1c40e
crash.kernel: use new KernelError exception to report errors during s…
jeffmahoney May 1, 2019
18707a4
crash.kernel: add debug option to load_modules
jeffmahoney May 1, 2019
823e505
crash.kernel: use objfile.has_symbols() to detect debuginfo
jeffmahoney May 1, 2019
58b7c35
crash.util: promote to be its own sub-package
jeffmahoney May 3, 2019
4175429
crash: add static percpu regions for modules
jeffmahoney May 1, 2019
40352e2
crash.kernel: handle failure to add module symbols
jeffmahoney May 1, 2019
9a86bc6
crash.kernel: improve and document debuginfo and module loading
jeffmahoney May 1, 2019
95b3d0d
crash.kernel: check module version on load
jeffmahoney Apr 26, 2019
917c3a9
crash.commands.task: allow 'task' command with no argument to show cu…
jeffmahoney May 2, 2019
a18e2b7
crash.infra.callbacks: explicitly connect to callbacks
jeffmahoney May 17, 2019
e0fa23e
crash.infra.lookup: move type name resolution into TypeCallback
jeffmahoney May 3, 2019
5dee123
crash.util.symbols: introduce simplified delayed lookups
jeffmahoney May 3, 2019
cc56e25
crash.subsystem.filesystem: add super_flags
jeffmahoney Apr 26, 2019
5f69e54
crash.subsystem.filesystem: add for_each_super_block, get_super_block
jeffmahoney Sep 18, 2018
7d72016
crash.subsystem.filesystem.mount: use type from symbol when available
jeffmahoney Sep 19, 2018
b4facc0
crash.subsystem.filesystem.mount: use crash.util.decode_flags
jeffmahoney May 4, 2019
b2817c9
crash.subsystem.filesystem: include sector number when describing dio…
jeffmahoney May 1, 2019
b7085be
crash.subsystem.{filesystem,storage}: refactor bio decoders
jeffmahoney May 3, 2019
c27620b
crash.types.vmstat: remove dead code
jeffmahoney May 6, 2019
fcb22c4
crash: remove CrashBaseClass
jeffmahoney May 3, 2019
30dd42b
crash.util: add more documentation
jeffmahoney May 20, 2019
65a7e06
crash: factor out task iteration
jeffmahoney May 7, 2019
abfd2dc
crash.commands: handle DelayedAttributeError gracefully
jeffmahoney May 8, 2019
62bb502
crash.commands.dmesg: handling dictionary string encoding better
jeffmahoney May 8, 2019
e7ff8dd
crash.types.slab: improve address printing
jeffmahoney May 9, 2019
6da88b1
crash.commands.kmem: use exceptions to exit command with error
jeffmahoney May 9, 2019
29ea504
crash.commands.kmem: fix argument parsing
jeffmahoney May 9, 2019
f2142e5
crash.commands.kmem: clean up some trivial things
jeffmahoney May 9, 2019
08749dd
crash.commands.ps: uncomment -G mode
jeffmahoney May 10, 2019
004ad94
crash: add kernel testing against vmcores
jeffmahoney May 7, 2019
cfac8fb
crash.types.classdev: update classdev iteration to use device_private
jeffmahoney May 7, 2019
39131e1
crash.subsystem.filesystems: add is_fstype_super and is_fstype_inode
jeffmahoney May 9, 2019
bfd2628
crash.subsystem.filesystem: document gdb.NotAvailableError
jeffmahoney May 15, 2019
c5691bf
crash.subsytem.filesystem.mount: add API documentation
jeffmahoney May 9, 2019
4e60c1c
crash.subsystem.filesystem.btrfs: add helpers for super, inode, and u…
jeffmahoney Apr 29, 2019
7e077de
crash.commands.btrfs: add basic btrfs command
jeffmahoney Sep 18, 2018
575d1ef
crash.subsystem.filesystem.xfs: Add basic XFS infra
jeffmahoney Sep 18, 2018
1522012
crash.commands.xfs: add basic xfs command
jeffmahoney Sep 18, 2018
5483d9f
crash.subsystem.storage.blocksq: add per-queue requests_in_flight call
jeffmahoney Apr 22, 2019
538acd1
crash.commands.lsmod: add basic lsmod command
jeffmahoney May 1, 2019
e7789d4
crash.types.task: get_stack_pointer should take thread_struct
jeffmahoney May 15, 2019
1d22d73
crash.types.task: add accessor-helpers
jeffmahoney May 15, 2019
af12734
crash.commands.ps: factor out formatting
jeffmahoney May 15, 2019
550c337
crash.cache.syscache: update config parsing
jeffmahoney May 9, 2019
d04844b
tests: silence as much noise as possible
jeffmahoney May 17, 2019
cb870bb
crash.util: fix get_typed_pointer semantics
jeffmahoney May 20, 2019
0f70ab1
crash.types.task: add documentation and static typing hints
jeffmahoney May 20, 2019
d6bc98b
crash: more documentation and typing
jeffmahoney May 21, 2019
2834470
WIP: Add initial support for "live" debugging
May 9, 2019
14529d1
WIP: Add new "kcore" target using "drgn" backend
sdimitro May 20, 2019
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
Prev Previous commit
Next Next commit
crash: remove CrashBaseClass
This commit removes CrashBaseClass from the project entirely.

This simplifies the code immensely and means contributors don't need
to understand and/or potentially debug the black magic behind the
namespace, implicit singleton, exporting, and type/symbol loading
in order to get started.

The pattern now is to use crash.types.symbols to declare a Types,
Symbols, Symvals, etc object at the top of the module that contains
any needed types or symbols.  These are still declared as an array
of names and the naming structure (e.g. struct_name_type) is the
same as with CrashBaseClass.  They just appear in separate collections
under separate names.  Most functions will be at the module level
and will reference these objects directly.  If a state object is
required, a class is still used but it can inherit from `object' instead.
If callbacks are used on class attributes (instead of instance attributes)
they must be declared outside of the class.

This allows us to eliminate many classes entirely and reduce others
to simple state holder classes.  In some cases, like with percpu,
it makes sense to just use module instance and marshall the calls from the
module level to the instance explicitly.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
  • Loading branch information
jeffmahoney committed May 21, 2019
commit fcb22c423780a8a898db63ddfe69e6184e76909a
19 changes: 8 additions & 11 deletions crash/addrxlat.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import gdb
import addrxlat
from crash.infra import CrashBaseClass, export
from crash.cache.syscache import utsname
from crash.util import offsetof

Expand Down Expand Up @@ -39,7 +38,7 @@ def cb_read32(self, faddr):
def cb_read64(self, faddr):
return int(gdb.Value(faddr.addr).cast(self.uint64_ptr).dereference())

class CrashAddressTranslation(CrashBaseClass):
class CrashAddressTranslation(object):
def __init__(self):
try:
>
Expand All @@ -62,14 +61,12 @@ def __init__(self):
self.is_non_auto = True
break

@export
def addrxlat_context(self):
return self.context
__impl = CrashAddressTranslation()
def addrxlat_context():
return __impl.context

@export
def addrxlat_system(self):
return self.system
def addrxlat_system():
return __impl.system

@export
def addrxlat_is_non_auto(self):
return self.is_non_auto
def addrxlat_is_non_auto():
return __impl.is_non_auto
4 changes: 2 additions & 2 deletions crash/cache/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
import glob
import importlib

from crash.infra import CrashBaseClass, autoload_submodules
from crash.infra import autoload_submodules

class CrashCache(CrashBaseClass):
class CrashCache(object):
def refresh(self):
pass

Expand Down
51 changes: 32 additions & 19 deletions crash/cache/syscache.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
from crash.exceptions import DelayedAttributeError
from crash.cache import CrashCache
from crash.util import array_size
from crash.infra import export
from crash.infra.lookup import get_delayed_lookup
from crash.util.symbols import Types, Symvals, SymbolCallbacks
from crash.infra.lookup import DelayedValue

class CrashUtsnameCache(CrashCache):
__symvals__ = [ 'init_uts_ns' ]
symvals = Symvals([ 'init_uts_ns' ])

def load_utsname(self):
self.utsname = self.init_uts_ns['name']
self.utsname = self.symvals.init_uts_ns['name']
return self.utsname

def init_utsname_cache(self):
Expand All @@ -43,8 +43,8 @@ def __getattr__(self, name):
return getattr(self.__class__, name)

class CrashConfigCache(CrashCache):
__types__ = [ 'char *' ]
__symvals__ = [ 'kernel_config_data' ]
types = Types([ 'char *' ])
symvals = Symvals([ 'kernel_config_data' ])

def __getattr__(self, name):
if name == 'config_buffer':
Expand All @@ -70,8 +70,8 @@ def decompress_config_buffer(self):
MAGIC_END = 'IKCFG_ED'

# Must cast it to char * to do the pointer arithmetic correctly
data_addr = self.kernel_config_data.address.cast(self.char_p_type)
data_len = self.kernel_config_data.type.sizeof
data_addr = self.symvals.kernel_config_data.address.cast(self.types.char_p_type)
data_len = self.symvals.kernel_config_data.type.sizeof

buf_len = len(MAGIC_START)
buf = self.read_buf_str(data_addr, buf_len)
Expand Down Expand Up @@ -119,14 +119,18 @@ def __getitem__(self, name):
return None

class CrashKernelCache(CrashCache):
__symvals__ = [ 'avenrun' ]
__symbol_callbacks__ = [
( 'jiffies', 'setup_jiffies' ),
( 'jiffies_64', 'setup_jiffies' ) ]
__delayed_values__ = [ 'jiffies' ]
symvals = Symvals([ 'avenrun' ])

jiffies_ready = False
adjust_jiffies = False

jiffies_dv = DelayedValue('jiffies')

@property
def jiffies(self):
v = self.jiffies_dv.get()
return v

def __init__(self, config):
CrashCache.__init__(self)
self.config = config
Expand Down Expand Up @@ -157,8 +161,8 @@ def format_loadavg(metrics):

def get_loadavg_values(self):
metrics = []
for index in range(0, array_size(self.avenrun)):
metrics.append(self.calculate_loadavg(self.avenrun[index]))
for index in range(0, array_size(self.symvals.avenrun)):
metrics.append(self.calculate_loadavg(self.symvals.avenrun[index]))

return metrics

Expand All @@ -170,6 +174,11 @@ def get_loadavg(self):
except DelayedAttributeError:
return "Unknown"

@classmethod
def set_jiffies(cls, value):
cls.jiffies_dv.value = None
cls.jiffies_dv.callback(value)

@classmethod
def setup_jiffies(cls, symbol):
if cls.jiffies_ready:
Expand All @@ -187,7 +196,7 @@ def setup_jiffies(cls, symbol):
jiffies = int(gdb.lookup_global_symbol('jiffies').value())
cls.adjust_jiffies = False

delayed = get_delayed_lookup(cls, 'jiffies').callback(jiffies)
cls.set_jiffies(jiffies)

def adjusted_jiffies(self):
if self.adjust_jiffies:
Expand All @@ -199,10 +208,14 @@ def get_uptime(self):
self.uptime = timedelta(seconds=self.adjusted_jiffies() // self.hz)
return self.uptime

@export
def jiffies_to_msec(self, jiffies):
return 1000 // self.hz * jiffies
symbol_cbs = SymbolCallbacks( [( 'jiffies',
CrashKernelCache.setup_jiffies ),
( 'jiffies_64',
CrashKernelCache.setup_jiffies ) ])

utsname = CrashUtsnameCache()
config = CrashConfigCache()
kernel = CrashKernelCache(config)

def jiffies_to_msec(jiffies):
return 1000 // kernel.hz * jiffies
4 changes: 1 addition & 3 deletions crash/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

from crash.infra import CrashBaseClass

import gdb

import os
Expand All @@ -20,7 +18,7 @@ class ArgumentParser(argparse.ArgumentParser):
def error(self, message):
raise CommandLineError(message)

class Command(CrashBaseClass, gdb.Command):
class Command(gdb.Command):
commands = {}
def __init__(self, name, parser=None):
self.name = "py" + name
Expand Down
37 changes: 19 additions & 18 deletions crash/commands/dmesg.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

from crash.commands import Command, ArgumentParser
from crash.exceptions import DelayedAttributeError
from crash.util.symbols import Types, Symvals

types = Types([ 'struct printk_log *' , 'char *' ])
symvals = Symvals([ 'log_buf', 'log_buf_len', 'log_first_idx', 'log_next_idx',
'clear_seq', 'log_first_seq', 'log_next_seq' ])

class LogTypeException(Exception):
pass
Expand Down Expand Up @@ -148,10 +153,6 @@ def __init__(self, name):
parser.format_usage = lambda: 'log [-tdm]\n'
Command.__init__(self, name, parser)

__types__ = [ 'struct printk_log *' , 'char *' ]
__symvals__ = [ 'log_buf', 'log_buf_len', 'log_first_idx', 'log_next_idx',
'clear_seq', 'log_first_seq', 'log_next_seq' ]

@classmethod
def filter_unstructured_log(cls, log, args):
lines = log.split('\n')
Expand All @@ -168,11 +169,11 @@ def filter_unstructured_log(cls, log, args):
return '\n'.join(lines)

def log_from_idx(self, logbuf, idx, dict_needed=False):
msg = (logbuf + idx).cast(self.printk_log_p_type)
msg = (logbuf + idx).cast(types.printk_log_p_type)

try:
textval = (msg.cast(self.char_p_type) +
self.printk_log_p_type.target().sizeof)
textval = (msg.cast(types.char_p_type) +
types.printk_log_p_type.target().sizeof)
text = textval.string(length=int(msg['text_len']))
except UnicodeDecodeError as e:
print(e)
Expand All @@ -197,8 +198,8 @@ def log_from_idx(self, logbuf, idx, dict_needed=False):

if dict_needed:
dict_len = int(msg['dict_len'])
d = (msg.cast(self.char_p_type) +
self.printk_log_p_type.target().sizeof + textlen)
d = (msg.cast(types.char_p_type) +
types.printk_log_p_type.target().sizeof + textlen)
s = ''

for i in range(0, dict_len):
Expand All @@ -214,19 +215,19 @@ def log_from_idx(self, logbuf, idx, dict_needed=False):

def get_log_msgs(self, dict_needed=False):
try:
idx = self.log_first_idx
idx = symvals.log_first_idx
except DelayedAttributeError as e:
raise LogTypeException('not structured log')

if self.clear_seq < self.log_first_seq:
self.clear_seq = self.log_first_seq
if symvals.clear_seq < symvals.log_first_seq:
symvals.clear_seq = symvals.log_first_seq


seq = self.clear_seq
idx = self.log_first_idx
seq = symvals.clear_seq
idx = symvals.log_first_idx

while seq < self.log_next_seq:
msg = self.log_from_idx(self.log_buf, idx, dict_needed)
while seq < symvals.log_next_seq:
msg = self.log_from_idx(symvals.log_buf, idx, dict_needed)
seq += 1
idx = msg['next']
yield msg
Expand All @@ -250,11 +251,11 @@ def handle_structured_log(self, args):
print('{}'.format(d.encode('string_escape')))

def handle_logbuf(self, args):
if self.log_buf_len and self.log_buf:
if symvals.log_buf_len and symvals.log_buf:
if args.d:
raise LogInvalidOption("Unstructured logs don't offer key/value pair support")

print(self.filter_unstructured_log(self.log_buf.string('utf-8', 'replace'), args))
print(self.filter_unstructured_log(symvals.log_buf.string('utf-8', 'replace'), args))

def execute(self, args):
try:
Expand Down
98 changes: 0 additions & 98 deletions crash/infra/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,106 +4,8 @@
import sys
import glob
import os.path
import inspect
import importlib

from crash.infra.lookup import DelayedLookups

class export_wrapper(object):
def __init__(self, mod, cls, func):
self.cls = cls
self.func = func

if not hasattr(mod, '_export_wrapper_singleton_dict'):
mod._export_wrapper_singleton_dict = {}
self.singleton_dict = mod._export_wrapper_singleton_dict

def __call__(self, *args, **kwargs):
try:
obj = self.singleton_dict[self.cls]
except KeyError:
obj = self.cls()
self.singleton_dict[self.cls] = obj

if isinstance(self.func, classmethod):
return self.func.__func__(self.cls, *args, **kwargs)
elif isinstance(self.func, staticmethod):
return self.func.__func__(*args, **kwargs)
else:
return self.func(obj, *args, **kwargs)

def register_singleton(mod, obj):
if not hasattr(mod, '_export_wrapper_singleton_dict'):
raise RuntimeError("Class {} has no exported members."
.format(obj.__class__.__name__))

mod._export_wrapper_singleton_dict[obj.__class__] = obj

def export(func):
"""This marks the function for export to the module namespace.
The class must inherit from CrashBaseClass."""
if isinstance(func, staticmethod) or isinstance(func, classmethod):
func.__func__.__export_to_module__ = True
else:
func.__export_to_module__ = True
return func

class _CrashBaseMeta(type):
"""
This metaclass handles both exporting methods to the module namespace
and handling asynchronous loading of types and symbols. To enable it,
all you need to do is define your class as follows:

class Foo(CrashBaseClass):
...

There are several special class variables that are interpreted during
class (not instance) creation.

The following create properties in the class that initially
raise MissingSymbolError but contain the requested information when
made available. The properties for types will be the name of the type,
with 'struct ' removed and _type appended. E.g. 'struct test' becomes
test_type. If it's a pointer type, _p is appended after the type name,
e.g. 'struct test *' becomes test_p_type. The properties for the symbols
are named with the symbol name. If there is a naming collision,
NameError is raised.
__types__ -- A list consisting of type names. Pointer are handled in
Pointer are handled in a manner similarly to how
they are handled in C code. e.g. 'char *'.
__symbols__ -- A list of symbol names
__minsymbols__ -- A list of minimal symbols
__symvals__ -- A list of symbol names that will return the value
associated with the symbol instead of the symbol itself.

The following set up callbacks when the requested type or symbol value
is available. These each accept a list of 2-tuples, (specifier, callback).
The callback is passed the type or symbol requested.
__type_callbacks__
__symbol_callbacks__
"""
def __new__(cls, name, parents, dct):
DelayedLookups.setup_delayed_lookups_for_class(name, dct)
return type.__new__(cls, name, parents, dct)

def __init__(cls, name, parents, dct):
super(_CrashBaseMeta, cls).__init__(name, parents, dct)
cls.setup_exports_for_class(cls, dct)
DelayedLookups.setup_named_callbacks(cls, dct)

@staticmethod
def setup_exports_for_class(cls, dct):
mod = sys.modules[dct['__module__']]
for name, decl in dct.items():
if (hasattr(decl, '__export_to_module__') or
((isinstance(decl, classmethod) or
isinstance(decl, staticmethod)) and
hasattr(decl.__func__, "__export_to_module__"))):
setattr(mod, name, export_wrapper(mod, cls, decl))

class CrashBaseClass(metaclass=_CrashBaseMeta):
pass

def autoload_submodules(caller, callback=None):
mods = []
try:
Expand Down
Loading