Source code for crash.commands.dmesg

# -*- coding: utf-8 -*-
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
"""
SUMMARY
-------

Display system message buffer

::

  log [-tdm]
  dmesg [-tdm]

DESCRIPTION
-----------

This command dumps the kernel ``log_buf`` contents in chronological order.
The command supports the older log_buf formats, which may or may not contain a
timestamp inserted prior to each message, as well as the newer variable-length
record format, where the timestamp is contained in each log entry's header.


  -t  Display the message text without the timestamp.
  -d  Display the dictionary of key/value pair properties that are
      optionally appended to a message by the kernel's dev_printk()
      function; only applicable to the variable-length record format.
  -m  Display the message log level in brackets preceding each message.
      For the variable-length record format, the level will be displayed
      in hexadecimal, and depending upon the kernel version, also contains
      the facility or flags bits.

EXAMPLES
--------

Dump the kernel message buffer:

::

  py-crash> log
  Linux version 2.2.5-15smp (root@mclinux1) (gcc version egcs-2.91.66 19990
  314/Linux (egcs-1.1.2 release)) #1 SMP Thu Aug 26 11:04:37 EDT 1999
  Intel MultiProcessor Specification v1.4
      Virtual Wire compatibility mode.
  OEM ID: DELL     Product ID: WS 410       APIC at: 0xFEE00000
  Processor #0 Pentium(tm) Pro APIC version 17
  Processor #1 Pentium(tm) Pro APIC version 17
  I/O APIC #2 Version 17 at 0xFEC00000.
  Processors: 2
  mapped APIC to ffffe000 (fee00000)
  mapped IOAPIC to ffffd000 (fec00000)
  Detected 447696347 Hz processor.
  Console: colour VGA+ 80x25
  Calibrating delay loop... 445.64 BogoMIPS
  ...
    8K byte-wide RAM 5:3 Rx:Tx split, autoselect/Autonegotiate interface.
    MII transceiver found at address 24, status 782d.
    Enabling bus-master transmits and whole-frame receives.
  Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
  nfsd_init: initialized fhcache, entries=256
  ...

Do the same thing, but also show the log level preceding each message:

::

  py-crash> log -m
  <4>Linux version 2.2.5-15smp (root@mclinux1) (gcc version egcs-2.91.66 19990
  314/Linux (egcs-1.1.2 release)) #1 SMP Thu Aug 26 11:04:37 EDT 1999
  <4>Intel MultiProcessor Specification v1.4
  <4>    Virtual Wire compatibility mode.
  <4>OEM ID: DELL     Product ID: WS 410       APIC at: 0xFEE00000
  <4>Processor #0 Pentium(tm) Pro APIC version 17
  <4>Processor #1 Pentium(tm) Pro APIC version 17
  <4>I/O APIC #2 Version 17 at 0xFEC00000.
  <4>Processors: 2
  <4>mapped APIC to ffffe000 (fee00000)
  <4>mapped IOAPIC to ffffd000 (fec00000)
  <4>Detected 447696347 Hz processor.
  <4>Console: colour VGA+ 80x25
  <4>Calibrating delay loop... 445.64 BogoMIPS
  ...
  <6>  8K byte-wide RAM 5:3 Rx:Tx split, autoselect/Autonegotiate interface.
  <6>  MII transceiver found at address 24, status 782d.
  <6>  Enabling bus-master transmits and whole-frame receives.
  <6>Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
  <7>nfsd_init: initialized fhcache, entries=256
  ...

On a system with the variable-length record format, and whose log_buf has been
filled and wrapped around, display the log with timestamp data:

::

  py-crash> log
  [    0.467730] pci 0000:ff:02.0: [8086:2c10] type 00 class 0x060000
  [    0.467749] pci 0000:ff:02.1: [8086:2c11] type 00 class 0x060000
  [    0.467769] pci 0000:ff:02.4: [8086:2c14] type 00 class 0x060000
  [    0.467788] pci 0000:ff:02.5: [8086:2c15] type 00 class 0x060000
  [    0.467809] pci 0000:ff:03.0: [8086:2c18] type 00 class 0x060000
  [    0.467828] pci 0000:ff:03.1: [8086:2c19] type 00 class 0x060000
  ...

Display the same message text as above, without the timestamp data:

::

  py-crash> log -t
  pci 0000:ff:02.0: [8086:2c10] type 00 class 0x060000
  pci 0000:ff:02.1: [8086:2c11] type 00 class 0x060000
  pci 0000:ff:02.4: [8086:2c14] type 00 class 0x060000
  pci 0000:ff:02.5: [8086:2c15] type 00 class 0x060000
  pci 0000:ff:03.0: [8086:2c18] type 00 class 0x060000
  pci 0000:ff:03.1: [8086:2c19] type 00 class 0x060000
  ...

Display the same message text as above, with appended dictionary data:

::

  py-crash> log -td
  pci 0000:ff:02.0: [8086:2c10] type 00 class 0x060000
  SUBSYSTEM=pci
  DEVICE=+pci:0000:ff:02.0
  pci 0000:ff:02.1: [8086:2c11] type 00 class 0x060000
  SUBSYSTEM=pci
  DEVICE=+pci:0000:ff:02.1
  pci 0000:ff:02.4: [8086:2c14] type 00 class 0x060000
  SUBSYSTEM=pci
  DEVICE=+pci:0000:ff:02.4
  pci 0000:ff:02.5: [8086:2c15] type 00 class 0x060000
  SUBSYSTEM=pci
  DEVICE=+pci:0000:ff:02.5
  pci 0000:ff:03.0: [8086:2c18] type 00 class 0x060000
  SUBSYSTEM=pci
  DEVICE=+pci:0000:ff:03.0
  pci 0000:ff:03.1: [8086:2c19] type 00 class 0x060000
  SUBSYSTEM=pci
  DEVICE=+pci:0000:ff:03.1
  ...
"""

from typing import Dict, Iterable, Any

import re
import argparse

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

import gdb

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'])

[docs]class LogTypeException(Exception): pass
[docs]class LogInvalidOption(Exception): pass
[docs]class LogCommand(Command): """dump system message buffer""" def __init__(self, name: str) -> None: parser = ArgumentParser(prog=name) parser.add_argument('-t', action='store_true', default=False) parser.add_argument('-d', action='store_true', default=False) parser.add_argument('-m', action='store_true', default=False) Command.__init__(self, name, parser)
[docs] @classmethod def filter_unstructured_log(cls, log: str, args: argparse.Namespace) -> str: lines = log.split('\n') if not args.m: newlog = [] for line in lines: if not args.m: line = re.sub(r'^<[0-9]+>', '', line) if args.t: line = re.sub(r'^\[[0-9\. ]+\] ', '', line) newlog.append(line) lines = newlog return '\n'.join(lines)
[docs] def log_from_idx(self, logbuf: gdb.Value, idx: int, dict_needed: bool = False) -> Dict: msg = (logbuf + idx).cast(types.printk_log_p_type) try: 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) msglen = int(msg['len']) # A zero-length message means we wrap back to the beginning if msglen == 0: nextidx = 0 else: nextidx = idx + msglen textlen = int(msg['text_len']) msgdict = { 'text' : text[0:textlen], 'timestamp' : int(msg['ts_nsec']), 'level' : int(msg['level']), 'next' : nextidx, 'dict' : [], } if dict_needed: dict_len = int(msg['dict_len']) d = (msg.cast(types.char_p_type) + types.printk_log_p_type.target().sizeof + textlen) if dict_len > 0: s = d.string('ascii', 'backslashreplace', dict_len) msgdict['dict'].append(s) return msgdict
[docs] def get_log_msgs(self, dict_needed: bool = False) -> Iterable[Dict[str, Any]]: try: idx = symvals.log_first_idx except DelayedAttributeError: raise LogTypeException('not structured log') if symvals.clear_seq < symvals.log_first_seq: # mypy seems to think the preceding clear_seq is fine but this # one isn't. Derp. symvals.clear_seq = symvals.log_first_seq # type: ignore seq = symvals.clear_seq idx = symvals.log_first_idx while seq < symvals.log_next_seq: msg = self.log_from_idx(symvals.log_buf, idx, dict_needed) seq += 1 idx = msg['next'] yield msg
[docs] def handle_structured_log(self, args: argparse.Namespace) -> None: for msg in self.get_log_msgs(args.d): timestamp = '' if not args.t: usecs = int(msg['timestamp']) timestamp = ('[{:5d}.{:06d}] ' .format(usecs // 1000000000, (usecs % 1000000000) // 1000)) level = '' if args.m: level = '<{:d}>'.format(msg['level']) for line in msg['text'].split('\n'): print('{}{}{}'.format(level, timestamp, line)) for d in msg['dict']: print(d)
[docs] def handle_logbuf(self, args: argparse.Namespace) -> None: 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(symvals.log_buf.string('utf-8', 'replace'), args))
[docs] def execute(self, args: argparse.Namespace) -> None: try: self.handle_structured_log(args) return except LogTypeException: pass try: self.handle_logbuf(args) return except LogTypeException: pass except LogInvalidOption as lio: raise CommandError(str(lio)) print("Can't find valid log") print(args)
LogCommand('log') LogCommand('dmesg')