Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
178 changes: 178 additions & 0 deletions crash/cache/sys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#!/usr/bin/env python
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

import gdb
import re
import zlib
from crash.cache import CrashCache

class GetSymbolException(Exception):
pass

class GetValueException(Exception):
pass

uchar = gdb.lookup_type('unsigned char')
ucharp = uchar.pointer()

class CrashCacheSys(CrashCache):

utsname_cache = None
ikconfig_raw_cache = None
ikconfig_cache = None
machdep_cache = None
kernel_cache = None

def read_buf(self, address, size):
return str(gdb.selected_inferior().read_memory(address, size))

def init_utsname_cache(self):
if self.utsname_cache:
return

try:
init_uts_ns = gdb.lookup_global_symbol('init_uts_ns').value()
utsname = init_uts_ns['name']
except Exception, e:
print "Error: Unable to locate utsname: %s" % (e)
raise GetSymbolException(e)

try:
self.utsname_cache = dict()
self.utsname_cache['nodename'] = utsname['nodename'].string()
self.utsname_cache['release'] = utsname['release'].string()
self.utsname_cache['version'] = utsname['version'].string()
self.utsname_cache['machine'] = utsname['machine'].string()
except Exception, e:
print "Error: Unable to locate utsname string: %s" % (e)
raise GetValueException(e)


def init_ikconfig_raw_cache(self):
if self.ikconfig_raw_cache:
return

MAGIC_START = 'IKCFG_ST'
MAGIC_END = 'IKCFG_ED'
GZIP_HEADER_LEN = 10

kernel_config_data_sym = gdb.lookup_symbol('kernel_config_data', block=None, domain=gdb.SYMBOL_VAR_DOMAIN)[0]
kernel_config_data = kernel_config_data_sym.value()
# Must cast it to ucharp to do the pointer arithmetic correctly
data_addr = kernel_config_data.address.cast(ucharp)
data_len = kernel_config_data_sym.type.sizeof

buf_len = len(MAGIC_START)
buf = self.read_buf(data_addr, buf_len)
if buf != MAGIC_START:
raise IOError("Missing MAGIC_START in kernel_config_data.")

buf_len = len(MAGIC_END)
buf = self.read_buf(data_addr + data_len - buf_len - 1, buf_len)
if buf != MAGIC_END:
raise IOError("Missing MAGIC_END in kernel_config_data.")

# Read the compressed data
#
# FIXME: We skip the gzip header (10 bytes) and decompress
# the data directly using zlib. If we know how to map
# the memory into a file/stream, it would be possible
# to use gzip module.
buf_len = data_len - len(MAGIC_START) - len(MAGIC_END) - GZIP_HEADER_LEN
buf = self.read_buf(data_addr + len(MAGIC_START) + GZIP_HEADER_LEN, buf_len)

self.ikconfig_raw_cache = zlib.decompress(buf, -15, buf_len)


def init_ikconfig_cache(self):
if self.ikconfig_cache:
return

if not self.ikconfig_raw_cache:
self.init_ikconfig_raw_cache()

self.ikconfig_cache = dict()

for line in self.ikconfig_raw_cache.splitlines():
# bin comments
line = re.sub("#.*$", "", line)
# bin white space at the beginning and the end of the line
line = re.sub("^\s*", "", line)
line = re.sub("\s*$", "", line)

if not line:
continue

items = re.split("=", line)
if len(items) == 2:
self.ikconfig_cache[items[0]] = items[1]
else:
print "Warning: did not parse kernel config line: %s" % (line)


def convert_time(self, jiffies):
SEC_MINUTES = 60
SEC_HOURS = 60 * SEC_MINUTES
SEC_DAYS = 24 * SEC_HOURS

total = jiffies / self.machdep_cache['hz']

days = total / SEC_DAYS
total %= SEC_DAYS
hours = total / SEC_HOURS
total %= SEC_HOURS
minutes = total / SEC_MINUTES
seconds = total % SEC_MINUTES

buf = ""
if days:
buf = "%d days, " % (days)
buf += "%02d:%02d:%02d" % (hours, minutes, seconds)

return buf

def get_uptime(self):
jiffies = gdb.lookup_global_symbol('jiffies_64').value()
if jiffies:
# FIXME: Only kernel above 2.6.0 initializes 64-bit jiffies
# value by 2^32 + 5 minutes
jiffies -= long(0x100000000) - 300 * self.machdep_cache['hz']
else:
jiffies = gdb.lookup_global_symbol('jiffies').value()

return self.convert_time(jiffies)


def init_machdep_cache(self):
if self.machdep_cache:
return

if not self.ikconfig_cache:
self.init_ikconfig_cache()

self.machdep_cache = dict()
self.machdep_cache["hz"] = long(self.ikconfig_cache["CONFIG_HZ"])


def init_kernel_cache(self):
if self.kernel_cache:
return

if not self.machdep_cache:
self.init_machdep_cache()

self.kernel_cache = dict()
self.kernel_cache["uptime"] = self.get_uptime()


def init_sys_caches(self):
self.init_utsname_cache()
self.init_kernel_cache()

def __init__(self):
super(CrashCacheSys, self).__init__()

def refresh(self):
pass

cache = CrashCacheSys()
81 changes: 81 additions & 0 deletions crash/commands/sys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env python
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

import gdb
from crash.commands import CrashCommand
from crash.cache import sys
import argparse

class LogTypeException(Exception):
pass

class LogInvalidOption(Exception):
pass

class SysCommand(CrashCommand):
"""system data

NAME
sys - system data

SYNOPSIS
sys [config]

DESCRIPTION
This command displays system-specific data. If no arguments are entered,
the same system data shown during crash invocation is shown.

config If the kernel was configured with CONFIG_IKCONFIG, then
dump the in-kernel configuration data.

EXAMPLES
Display essential system information:

crash> sys config
KERNEL: vmlinux.4
DUMPFILE: lcore.cr.4
CPUS: 4
DATE: Mon Oct 11 18:48:55 1999
UPTIME: 10 days, 14:14:39
LOAD AVERAGE: 0.74, 0.23, 0.08
TASKS: 77
NODENAME: test.mclinux.com
RELEASE: 2.2.5-15smp
VERSION: #24 SMP Mon Oct 11 17:41:40 CDT 1999
MACHINE: i686 (500 MHz)
MEMORY: 1 GB


"""
def __init__(self, name):

parser = argparse.ArgumentParser(prog=name)

parser.add_argument('config', nargs='?')

parser.format_usage = lambda : "sys [config]\n"
CrashCommand.__init__(self, name, parser)


def show_default(self):
print " UPTIME: %s" % (sys.cache.kernel_cache['uptime'])
print " NODENAME: %s" % (sys.cache.utsname_cache['nodename'])
print " RELEASE: %s" % (sys.cache.utsname_cache['release'])
print " VERSION: %s" % (sys.cache.utsname_cache['version'])
print " MACHINE: %s" % (sys.cache.utsname_cache['machine'])

def show_raw_ikconfig(self):
print sys.cache.ikconfig_raw_cache

def execute(self, args):
sys.cache.init_sys_caches()

if args.config:
if args.config == "config":
self.show_raw_ikconfig()
else:
print "Error: unknown option: %s" % (args.config)
else:
self.show_default()

SysCommand("sys")