scripts/gdb: lx-dmesg: read records individually

For the gdb command lx-dmesg, the entire descriptor, info, and text
data regions are read into memory before printing any records. For
large kernel log buffers, this not only causes a huge delay before
seeing any records, but it may also lead to python errors of too
much memory allocation.

Rather than reading in all these regions in advance, read them as
needed and only read the regions for the particular record that is
being printed.

The gdb macro "dmesg" in Documentation/admin-guide/kdump/gdbmacros.txt
already prints out the kernel log buffer like this.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/874k79c3a9.fsf@jogness.linutronix.de
This commit is contained in:
John Ogness 2021-12-15 16:16:22 +01:06 committed by Petr Mladek
parent 52e68cd60d
commit deaee2704a
1 changed files with 18 additions and 17 deletions

View File

@ -44,19 +44,17 @@ class LxDmesg(gdb.Command):
sz = prb_desc_ring_type.get_type().sizeof sz = prb_desc_ring_type.get_type().sizeof
desc_ring = utils.read_memoryview(inf, addr, sz).tobytes() desc_ring = utils.read_memoryview(inf, addr, sz).tobytes()
# read in descriptor array # read in descriptor count, size, and address
off = prb_desc_ring_type.get_type()['count_bits'].bitpos // 8 off = prb_desc_ring_type.get_type()['count_bits'].bitpos // 8
desc_ring_count = 1 << utils.read_u32(desc_ring, off) desc_ring_count = 1 << utils.read_u32(desc_ring, off)
desc_sz = prb_desc_type.get_type().sizeof desc_sz = prb_desc_type.get_type().sizeof
off = prb_desc_ring_type.get_type()['descs'].bitpos // 8 off = prb_desc_ring_type.get_type()['descs'].bitpos // 8
addr = utils.read_ulong(desc_ring, off) desc_addr = utils.read_ulong(desc_ring, off)
descs = utils.read_memoryview(inf, addr, desc_sz * desc_ring_count).tobytes()
# read in info array # read in info size and address
info_sz = printk_info_type.get_type().sizeof info_sz = printk_info_type.get_type().sizeof
off = prb_desc_ring_type.get_type()['infos'].bitpos // 8 off = prb_desc_ring_type.get_type()['infos'].bitpos // 8
addr = utils.read_ulong(desc_ring, off) info_addr = utils.read_ulong(desc_ring, off)
infos = utils.read_memoryview(inf, addr, info_sz * desc_ring_count).tobytes()
# read in text data ring structure # read in text data ring structure
off = printk_ringbuffer_type.get_type()['text_data_ring'].bitpos // 8 off = printk_ringbuffer_type.get_type()['text_data_ring'].bitpos // 8
@ -64,12 +62,11 @@ class LxDmesg(gdb.Command):
sz = prb_data_ring_type.get_type().sizeof sz = prb_data_ring_type.get_type().sizeof
text_data_ring = utils.read_memoryview(inf, addr, sz).tobytes() text_data_ring = utils.read_memoryview(inf, addr, sz).tobytes()
# read in text data # read in text data size and address
off = prb_data_ring_type.get_type()['size_bits'].bitpos // 8 off = prb_data_ring_type.get_type()['size_bits'].bitpos // 8
text_data_sz = 1 << utils.read_u32(text_data_ring, off) text_data_sz = 1 << utils.read_u32(text_data_ring, off)
off = prb_data_ring_type.get_type()['data'].bitpos // 8 off = prb_data_ring_type.get_type()['data'].bitpos // 8
addr = utils.read_ulong(text_data_ring, off) text_data_addr = utils.read_ulong(text_data_ring, off)
text_data = utils.read_memoryview(inf, addr, text_data_sz).tobytes()
counter_off = atomic_long_type.get_type()['counter'].bitpos // 8 counter_off = atomic_long_type.get_type()['counter'].bitpos // 8
@ -102,17 +99,20 @@ class LxDmesg(gdb.Command):
desc_off = desc_sz * ind desc_off = desc_sz * ind
info_off = info_sz * ind info_off = info_sz * ind
desc = utils.read_memoryview(inf, desc_addr + desc_off, desc_sz).tobytes()
# skip non-committed record # skip non-committed record
state = 3 & (utils.read_u64(descs, desc_off + sv_off + state = 3 & (utils.read_u64(desc, sv_off + counter_off) >> desc_flags_shift)
counter_off) >> desc_flags_shift)
if state != desc_committed and state != desc_finalized: if state != desc_committed and state != desc_finalized:
if did == head_id: if did == head_id:
break break
did = (did + 1) & desc_id_mask did = (did + 1) & desc_id_mask
continue continue
begin = utils.read_ulong(descs, desc_off + begin_off) % text_data_sz begin = utils.read_ulong(desc, begin_off) % text_data_sz
end = utils.read_ulong(descs, desc_off + next_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 # handle data-less record
if begin & 1 == 1: if begin & 1 == 1:
@ -125,16 +125,17 @@ class LxDmesg(gdb.Command):
# skip over descriptor id # skip over descriptor id
text_start = begin + utils.get_long_type().sizeof text_start = begin + utils.get_long_type().sizeof
text_len = utils.read_u16(infos, info_off + len_off) text_len = utils.read_u16(info, len_off)
# handle truncated message # handle truncated message
if end - text_start < text_len: if end - text_start < text_len:
text_len = end - text_start text_len = end - text_start
text = text_data[text_start:text_start + text_len].decode( text_data = utils.read_memoryview(inf, text_data_addr + text_start,
encoding='utf8', errors='replace') text_len).tobytes()
text = text_data[0:text_len].decode(encoding='utf8', errors='replace')
time_stamp = utils.read_u64(infos, info_off + ts_off) time_stamp = utils.read_u64(info, ts_off)
for line in text.splitlines(): for line in text.splitlines():
msg = u"[{time:12.6f}] {line}\n".format( msg = u"[{time:12.6f}] {line}\n".format(