| # | 
 | # gdb helper commands and functions for Linux kernel debugging | 
 | # | 
 | #  kernel log buffer dump | 
 | # | 
 | # Copyright (c) Siemens AG, 2011, 2012 | 
 | # | 
 | # Authors: | 
 | #  Jan Kiszka <jan.kiszka@siemens.com> | 
 | # | 
 | # This work is licensed under the terms of the GNU GPL version 2. | 
 | # | 
 |  | 
 | import gdb | 
 | import sys | 
 |  | 
 | from linux import utils | 
 |  | 
 | printk_info_type = utils.CachedType("struct printk_info") | 
 | prb_data_blk_lpos_type = utils.CachedType("struct prb_data_blk_lpos") | 
 | prb_desc_type = utils.CachedType("struct prb_desc") | 
 | prb_desc_ring_type = utils.CachedType("struct prb_desc_ring") | 
 | prb_data_ring_type = utils.CachedType("struct prb_data_ring") | 
 | printk_ringbuffer_type = utils.CachedType("struct printk_ringbuffer") | 
 |  | 
 | class LxDmesg(gdb.Command): | 
 |     """Print Linux kernel log buffer.""" | 
 |  | 
 |     def __init__(self): | 
 |         super(LxDmesg, self).__init__("lx-dmesg", gdb.COMMAND_DATA) | 
 |  | 
 |     def invoke(self, arg, from_tty): | 
 |         inf = gdb.inferiors()[0] | 
 |  | 
 |         # read in prb structure | 
 |         prb_addr = int(str(gdb.parse_and_eval("(void *)'printk.c'::prb")).split()[0], 16) | 
 |         sz = printk_ringbuffer_type.get_type().sizeof | 
 |         prb = utils.read_memoryview(inf, prb_addr, sz).tobytes() | 
 |  | 
 |         # read in descriptor ring structure | 
 |         off = printk_ringbuffer_type.get_type()['desc_ring'].bitpos // 8 | 
 |         addr = prb_addr + off | 
 |         sz = prb_desc_ring_type.get_type().sizeof | 
 |         desc_ring = utils.read_memoryview(inf, addr, sz).tobytes() | 
 |  | 
 |         # read in descriptor count, size, and address | 
 |         off = prb_desc_ring_type.get_type()['count_bits'].bitpos // 8 | 
 |         desc_ring_count = 1 << utils.read_u32(desc_ring, off) | 
 |         desc_sz = prb_desc_type.get_type().sizeof | 
 |         off = prb_desc_ring_type.get_type()['descs'].bitpos // 8 | 
 |         desc_addr = utils.read_ulong(desc_ring, off) | 
 |  | 
 |         # read in info size and address | 
 |         info_sz = printk_info_type.get_type().sizeof | 
 |         off = prb_desc_ring_type.get_type()['infos'].bitpos // 8 | 
 |         info_addr = utils.read_ulong(desc_ring, off) | 
 |  | 
 |         # read in text data ring structure | 
 |         off = printk_ringbuffer_type.get_type()['text_data_ring'].bitpos // 8 | 
 |         addr = prb_addr + off | 
 |         sz = prb_data_ring_type.get_type().sizeof | 
 |         text_data_ring = utils.read_memoryview(inf, addr, sz).tobytes() | 
 |  | 
 |         # read in text data size and address | 
 |         off = prb_data_ring_type.get_type()['size_bits'].bitpos // 8 | 
 |         text_data_sz = 1 << utils.read_u32(text_data_ring, off) | 
 |         off = prb_data_ring_type.get_type()['data'].bitpos // 8 | 
 |         text_data_addr = utils.read_ulong(text_data_ring, off) | 
 |  | 
 |         sv_off = prb_desc_type.get_type()['state_var'].bitpos // 8 | 
 |  | 
 |         off = prb_desc_type.get_type()['text_blk_lpos'].bitpos // 8 | 
 |         begin_off = off + (prb_data_blk_lpos_type.get_type()['begin'].bitpos // 8) | 
 |         next_off = off + (prb_data_blk_lpos_type.get_type()['next'].bitpos // 8) | 
 |  | 
 |         ts_off = printk_info_type.get_type()['ts_nsec'].bitpos // 8 | 
 |         len_off = printk_info_type.get_type()['text_len'].bitpos // 8 | 
 |  | 
 |         # definitions from kernel/printk/printk_ringbuffer.h | 
 |         desc_committed = 1 | 
 |         desc_finalized = 2 | 
 |         desc_sv_bits = utils.get_long_type().sizeof * 8 | 
 |         desc_flags_shift = desc_sv_bits - 2 | 
 |         desc_flags_mask = 3 << desc_flags_shift | 
 |         desc_id_mask = ~desc_flags_mask | 
 |  | 
 |         # read in tail and head descriptor ids | 
 |         off = prb_desc_ring_type.get_type()['tail_id'].bitpos // 8 | 
 |         tail_id = utils.read_atomic_long(desc_ring, off) | 
 |         off = prb_desc_ring_type.get_type()['head_id'].bitpos // 8 | 
 |         head_id = utils.read_atomic_long(desc_ring, off) | 
 |  | 
 |         did = tail_id | 
 |         while True: | 
 |             ind = did % desc_ring_count | 
 |             desc_off = desc_sz * ind | 
 |             info_off = info_sz * ind | 
 |  | 
 |             desc = utils.read_memoryview(inf, desc_addr + desc_off, desc_sz).tobytes() | 
 |  | 
 |             # skip non-committed record | 
 |             state = 3 & (utils.read_atomic_long(desc, sv_off) >> desc_flags_shift) | 
 |             if state != desc_committed and state != desc_finalized: | 
 |                 if did == head_id: | 
 |                     break | 
 |                 did = (did + 1) & desc_id_mask | 
 |                 continue | 
 |  | 
 |             begin = utils.read_ulong(desc, begin_off) % text_data_sz | 
 |             end = utils.read_ulong(desc, next_off) % text_data_sz | 
 |  | 
 |             info = utils.read_memoryview(inf, info_addr + info_off, info_sz).tobytes() | 
 |  | 
 |             # handle data-less record | 
 |             if begin & 1 == 1: | 
 |                 text = "" | 
 |             else: | 
 |                 # handle wrapping data block | 
 |                 if begin > end: | 
 |                     begin = 0 | 
 |  | 
 |                 # skip over descriptor id | 
 |                 text_start = begin + utils.get_long_type().sizeof | 
 |  | 
 |                 text_len = utils.read_u16(info, len_off) | 
 |  | 
 |                 # handle truncated message | 
 |                 if end - text_start < text_len: | 
 |                     text_len = end - text_start | 
 |  | 
 |                 text_data = utils.read_memoryview(inf, text_data_addr + text_start, | 
 |                                                   text_len).tobytes() | 
 |                 text = text_data[0:text_len].decode(encoding='utf8', errors='replace') | 
 |  | 
 |             time_stamp = utils.read_u64(info, ts_off) | 
 |  | 
 |             for line in text.splitlines(): | 
 |                 msg = u"[{time:12.6f}] {line}\n".format( | 
 |                     time=time_stamp / 1000000000.0, | 
 |                     line=line) | 
 |                 # With python2 gdb.write will attempt to convert unicode to | 
 |                 # ascii and might fail so pass an utf8-encoded str instead. | 
 |                 if sys.hexversion < 0x03000000: | 
 |                     msg = msg.encode(encoding='utf8', errors='replace') | 
 |                 gdb.write(msg) | 
 |  | 
 |             if did == head_id: | 
 |                 break | 
 |             did = (did + 1) & desc_id_mask | 
 |  | 
 |  | 
 | LxDmesg() |