1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# gdb helper commands and functions for Linux kernel debugging 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# kernel log buffer dump 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun# Copyright (c) Siemens AG, 2011, 2012 7*4882a593Smuzhiyun# 8*4882a593Smuzhiyun# Authors: 9*4882a593Smuzhiyun# Jan Kiszka <jan.kiszka@siemens.com> 10*4882a593Smuzhiyun# 11*4882a593Smuzhiyun# This work is licensed under the terms of the GNU GPL version 2. 12*4882a593Smuzhiyun# 13*4882a593Smuzhiyun 14*4882a593Smuzhiyunimport gdb 15*4882a593Smuzhiyunimport sys 16*4882a593Smuzhiyun 17*4882a593Smuzhiyunfrom linux import utils 18*4882a593Smuzhiyun 19*4882a593Smuzhiyunprintk_info_type = utils.CachedType("struct printk_info") 20*4882a593Smuzhiyunprb_data_blk_lpos_type = utils.CachedType("struct prb_data_blk_lpos") 21*4882a593Smuzhiyunprb_desc_type = utils.CachedType("struct prb_desc") 22*4882a593Smuzhiyunprb_desc_ring_type = utils.CachedType("struct prb_desc_ring") 23*4882a593Smuzhiyunprb_data_ring_type = utils.CachedType("struct prb_data_ring") 24*4882a593Smuzhiyunprintk_ringbuffer_type = utils.CachedType("struct printk_ringbuffer") 25*4882a593Smuzhiyunatomic_long_type = utils.CachedType("atomic_long_t") 26*4882a593Smuzhiyun 27*4882a593Smuzhiyunclass LxDmesg(gdb.Command): 28*4882a593Smuzhiyun """Print Linux kernel log buffer.""" 29*4882a593Smuzhiyun 30*4882a593Smuzhiyun def __init__(self): 31*4882a593Smuzhiyun super(LxDmesg, self).__init__("lx-dmesg", gdb.COMMAND_DATA) 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun def invoke(self, arg, from_tty): 34*4882a593Smuzhiyun inf = gdb.inferiors()[0] 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun # read in prb structure 37*4882a593Smuzhiyun prb_addr = int(str(gdb.parse_and_eval("(void *)'printk.c'::prb")).split()[0], 16) 38*4882a593Smuzhiyun sz = printk_ringbuffer_type.get_type().sizeof 39*4882a593Smuzhiyun prb = utils.read_memoryview(inf, prb_addr, sz).tobytes() 40*4882a593Smuzhiyun 41*4882a593Smuzhiyun # read in descriptor ring structure 42*4882a593Smuzhiyun off = printk_ringbuffer_type.get_type()['desc_ring'].bitpos // 8 43*4882a593Smuzhiyun addr = prb_addr + off 44*4882a593Smuzhiyun sz = prb_desc_ring_type.get_type().sizeof 45*4882a593Smuzhiyun desc_ring = utils.read_memoryview(inf, addr, sz).tobytes() 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun # read in descriptor array 48*4882a593Smuzhiyun off = prb_desc_ring_type.get_type()['count_bits'].bitpos // 8 49*4882a593Smuzhiyun desc_ring_count = 1 << utils.read_u32(desc_ring, off) 50*4882a593Smuzhiyun desc_sz = prb_desc_type.get_type().sizeof 51*4882a593Smuzhiyun off = prb_desc_ring_type.get_type()['descs'].bitpos // 8 52*4882a593Smuzhiyun addr = utils.read_ulong(desc_ring, off) 53*4882a593Smuzhiyun descs = utils.read_memoryview(inf, addr, desc_sz * desc_ring_count).tobytes() 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun # read in info array 56*4882a593Smuzhiyun info_sz = printk_info_type.get_type().sizeof 57*4882a593Smuzhiyun off = prb_desc_ring_type.get_type()['infos'].bitpos // 8 58*4882a593Smuzhiyun addr = utils.read_ulong(desc_ring, off) 59*4882a593Smuzhiyun infos = utils.read_memoryview(inf, addr, info_sz * desc_ring_count).tobytes() 60*4882a593Smuzhiyun 61*4882a593Smuzhiyun # read in text data ring structure 62*4882a593Smuzhiyun off = printk_ringbuffer_type.get_type()['text_data_ring'].bitpos // 8 63*4882a593Smuzhiyun addr = prb_addr + off 64*4882a593Smuzhiyun sz = prb_data_ring_type.get_type().sizeof 65*4882a593Smuzhiyun text_data_ring = utils.read_memoryview(inf, addr, sz).tobytes() 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun # read in text data 68*4882a593Smuzhiyun off = prb_data_ring_type.get_type()['size_bits'].bitpos // 8 69*4882a593Smuzhiyun text_data_sz = 1 << utils.read_u32(text_data_ring, off) 70*4882a593Smuzhiyun off = prb_data_ring_type.get_type()['data'].bitpos // 8 71*4882a593Smuzhiyun addr = utils.read_ulong(text_data_ring, off) 72*4882a593Smuzhiyun text_data = utils.read_memoryview(inf, addr, text_data_sz).tobytes() 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun counter_off = atomic_long_type.get_type()['counter'].bitpos // 8 75*4882a593Smuzhiyun 76*4882a593Smuzhiyun sv_off = prb_desc_type.get_type()['state_var'].bitpos // 8 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun off = prb_desc_type.get_type()['text_blk_lpos'].bitpos // 8 79*4882a593Smuzhiyun begin_off = off + (prb_data_blk_lpos_type.get_type()['begin'].bitpos // 8) 80*4882a593Smuzhiyun next_off = off + (prb_data_blk_lpos_type.get_type()['next'].bitpos // 8) 81*4882a593Smuzhiyun 82*4882a593Smuzhiyun ts_off = printk_info_type.get_type()['ts_nsec'].bitpos // 8 83*4882a593Smuzhiyun len_off = printk_info_type.get_type()['text_len'].bitpos // 8 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun # definitions from kernel/printk/printk_ringbuffer.h 86*4882a593Smuzhiyun desc_committed = 1 87*4882a593Smuzhiyun desc_finalized = 2 88*4882a593Smuzhiyun desc_sv_bits = utils.get_long_type().sizeof * 8 89*4882a593Smuzhiyun desc_flags_shift = desc_sv_bits - 2 90*4882a593Smuzhiyun desc_flags_mask = 3 << desc_flags_shift 91*4882a593Smuzhiyun desc_id_mask = ~desc_flags_mask 92*4882a593Smuzhiyun 93*4882a593Smuzhiyun # read in tail and head descriptor ids 94*4882a593Smuzhiyun off = prb_desc_ring_type.get_type()['tail_id'].bitpos // 8 95*4882a593Smuzhiyun tail_id = utils.read_u64(desc_ring, off + counter_off) 96*4882a593Smuzhiyun off = prb_desc_ring_type.get_type()['head_id'].bitpos // 8 97*4882a593Smuzhiyun head_id = utils.read_u64(desc_ring, off + counter_off) 98*4882a593Smuzhiyun 99*4882a593Smuzhiyun did = tail_id 100*4882a593Smuzhiyun while True: 101*4882a593Smuzhiyun ind = did % desc_ring_count 102*4882a593Smuzhiyun desc_off = desc_sz * ind 103*4882a593Smuzhiyun info_off = info_sz * ind 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun # skip non-committed record 106*4882a593Smuzhiyun state = 3 & (utils.read_u64(descs, desc_off + sv_off + 107*4882a593Smuzhiyun counter_off) >> desc_flags_shift) 108*4882a593Smuzhiyun if state != desc_committed and state != desc_finalized: 109*4882a593Smuzhiyun if did == head_id: 110*4882a593Smuzhiyun break 111*4882a593Smuzhiyun did = (did + 1) & desc_id_mask 112*4882a593Smuzhiyun continue 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun begin = utils.read_ulong(descs, desc_off + begin_off) % text_data_sz 115*4882a593Smuzhiyun end = utils.read_ulong(descs, desc_off + next_off) % text_data_sz 116*4882a593Smuzhiyun 117*4882a593Smuzhiyun # handle data-less record 118*4882a593Smuzhiyun if begin & 1 == 1: 119*4882a593Smuzhiyun text = "" 120*4882a593Smuzhiyun else: 121*4882a593Smuzhiyun # handle wrapping data block 122*4882a593Smuzhiyun if begin > end: 123*4882a593Smuzhiyun begin = 0 124*4882a593Smuzhiyun 125*4882a593Smuzhiyun # skip over descriptor id 126*4882a593Smuzhiyun text_start = begin + utils.get_long_type().sizeof 127*4882a593Smuzhiyun 128*4882a593Smuzhiyun text_len = utils.read_u16(infos, info_off + len_off) 129*4882a593Smuzhiyun 130*4882a593Smuzhiyun # handle truncated message 131*4882a593Smuzhiyun if end - text_start < text_len: 132*4882a593Smuzhiyun text_len = end - text_start 133*4882a593Smuzhiyun 134*4882a593Smuzhiyun text = text_data[text_start:text_start + text_len].decode( 135*4882a593Smuzhiyun encoding='utf8', errors='replace') 136*4882a593Smuzhiyun 137*4882a593Smuzhiyun time_stamp = utils.read_u64(infos, info_off + ts_off) 138*4882a593Smuzhiyun 139*4882a593Smuzhiyun for line in text.splitlines(): 140*4882a593Smuzhiyun msg = u"[{time:12.6f}] {line}\n".format( 141*4882a593Smuzhiyun time=time_stamp / 1000000000.0, 142*4882a593Smuzhiyun line=line) 143*4882a593Smuzhiyun # With python2 gdb.write will attempt to convert unicode to 144*4882a593Smuzhiyun # ascii and might fail so pass an utf8-encoded str instead. 145*4882a593Smuzhiyun if sys.hexversion < 0x03000000: 146*4882a593Smuzhiyun msg = msg.encode(encoding='utf8', errors='replace') 147*4882a593Smuzhiyun gdb.write(msg) 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun if did == head_id: 150*4882a593Smuzhiyun break 151*4882a593Smuzhiyun did = (did + 1) & desc_id_mask 152*4882a593Smuzhiyun 153*4882a593Smuzhiyun 154*4882a593SmuzhiyunLxDmesg() 155