Пример #1
0
def test_rd(kdb):
	'''Test the `rd` command.

	Grab the contents of the register set and (optionally) perform a
	per-arch sanity test. The actual call to the rd command happens
	inside the library code in ktest.py [get_regs_kdb()]. However it is
	worth pulling out into a seperate test because other tests won't fail
	in such an easily understood way if there were a regression in the
	output of `rd`.
	'''
	c = kdb.console.enter_kdb()
	try:
		regs = c.get_regs()

		if kbuild.get_arch() == 'arm64':
			assert 'x0' in regs
			assert regs['sp'].startswith('ffff')
			assert regs['pc'].startswith('ffff')
		elif kbuild.get_arch == 'riscv':
			assert regs['sp'].startswith('ffff')
			assert regs['pc'].startswith('ffff')
		elif kbuild.get_arch() == 'x86':
			assert 'ax' in regs
			assert regs['sp'].startswith('ffff')
			assert regs['ip'].startswith('ffff')
	finally:
		c.exit_kdb()
Пример #2
0
def test_earlycon():
    kbuild.config(kgdb=True)
    kbuild.build()

    # Handle platforms that cannot auto-configure the earlycon
    arch = kbuild.get_arch()
    if 'x86' == arch:
        earlycon = "earlycon=uart8250,io,0x3f8"
    elif 'arm' == arch:
        earlycon = "earlycon=pl011,0x1c090000"
    else:
        earlycon = "earlycon"

    qemu = ktest.qemu(append=f'{earlycon} kgdboc_earlycon kgdbwait')
    console = qemu.console

    def expect_and_page(c, needle):
        choices = [needle, 'more>']

        choice = c.expect(choices)
        while choice == 1:
            c.send(' ')
            choice = c.expect(choices)
            print(choice)
            print(choices)
        print("Done")

    # This test is too low level to use the regular console helpers
    console.expect_kdb()
    console.sendline_kdb('bt')
    if 'x86' in kbuild.get_arch():
        # x86 uses earlycon with arguments and supports very early
        # consoles, expect to break whilst parsing early parameters
        expect_and_page(console, 'parse_early_param')
    elif 'arm64' in kbuild.get_arch():
        # Currently arm64 doesn't implement ARCH_HAS_EARLY_DEBUG
        # expect_and_page(console, 'console_init')
        pass
    expect_and_page(console, 'start_kernel')
    console.expect_kdb()
    console.sendline_kdb('go')

    # At this point kgdb has already fired up (on the earlycon). That
    # means the early boot messages have already passed by, hence we
    # need to set skip_early in the boot expectations.
    qemu.console.expect_boot(skip_early=True)
    qemu.console.expect_busybox()
    qemu.close()
Пример #3
0
def expect_boot(self, bootloader=(), skip_early=False, skip_late=False):
	for msg in bootloader:
		self.expect(msg)

	if not skip_early:
		self.expect('Linux version.*$')
		self.expect('Calibrating delay loop')

	# Initramfs decompression can take a long time (especially on a
	# TCG based VM on a busy machine). Extend the timeout until
	# the next console interaction...
	self.expect('[Uu]npack.*initramfs')
	self.timeout *= 2

	if not skip_late:
		# Memory is not *always* freed after unpacking the initramfs so
		# we must also look for other common messages that indicate we
		# moved on from unpacking the initramfs.
		self.expect(['Freeing initrd memory',
			     'io scheduler.*registered',
			     'Registered I/O driver kgdboc'])

		# We need a wildcard here because some newer kernels now say:
		# "Free unused kernel image memory".
		self.expect('Freeing unused kernel.*memory')

		# Restore the normal timeout
		self.timeout = self.default_timeout

	# Reset the terminal when running in platforms whose bootloader
	# output screws up the handling of line breaks... a bit gross
	# but makes reading the diagnostic output less painful!
	arch = kbuild.get_arch()
	if arch == 'x86':
		os.system('reset')
Пример #4
0
def test_kgdb():
    '''High-level kgdb smoke test.

	Tour a number of kgdb features to prove that basic functionality
	if working OK.
	'''

    kbuild.config(kgdb=True)
    kbuild.build()

    qemu = ktest.qemu(second_uart=True, gdb=True, append='kgdbwait')
    console = qemu.console
    gdb = qemu.debug

    console.expect_boot(skip_late=True)
    console.expect('Waiting for connection from remote gdb...')
    gdb.connect_to_target()

    gdb.send('where\r')
    gdb.expect('kgdb_initial_breakpoint')
    gdb.expect(['init_kgdboc', 'configure_kgdboc'])
    gdb.expect_prompt()

    gdb.send('break do_sys_open\r')
    gdb.expect_prompt()

    gdb.send('continue\r')
    gdb.expect('hit Breakpoint')
    gdb.expect_prompt()

    gdb.send('info registers\r')
    # If the PC is not automatically shown symbolically in a
    # register dump then we must look it up explicitly.
    if kbuild.get_arch() in ('mips', ):
        gdb.expect_prompt()
        gdb.send('info symbol $pc\r')
    # On x86_64 the PC lookup for this is __x64_sys_open (and on mips
    # it can be sys_open so we don't expect the 'do_'!
    gdb.expect('sys_open')
    gdb.expect_prompt()

    gdb.send('info thread\r')
    gdb.expect('oom_reaper')
    gdb.expect_prompt()

    gdb.send('thread 10\r')
    gdb.expect_prompt()
    gdb.send('where\r')
    gdb.expect('kthread')
    gdb.expect(['ret_from_fork', 'ret_from_kernel_thread', 'riscv.*entry[.]S'])
    gdb.expect_prompt()

    gdb.send('delete 1\r')
    gdb.expect_prompt()

    gdb.send('continue\r')
    console.expect_busybox()

    qemu.close()
Пример #5
0
def test_info_registers(kgdb):
	(console, gdb) = kgdb.enter_gdb()
	try:
		gdb.sendline('info registers')
		# Without doing architecture specific checks we can
		# only really look for the PC/IP being inside the
		# kgdb_breakpoint function (and even that doesn't work
		# for architectures where the PC doesn't get shown
		# symbolically).
		if kbuild.get_arch() not in ('mips',):
			gdb.expect('kgdb_breakpoint')
	finally:
		gdb.expect_prompt()
		kgdb.exit_gdb()
Пример #6
0
def test_WARNING(kdb):
    '''
	Test that kdb does *not* enter during a WARN_ON()
	'''

    kdb.console.sendline(
        'echo WARNING > /sys/kernel/debug/provoke-crash/DIRECT')
    kdb.console.expect('WARNING')
    #kdb.console.expect('lkdtm_WARNING')

    # riscv doesn't issue stack trace on warnings
    if kbuild.get_arch() != 'riscv':
        kdb.console.expect('vfs_write')

    kdb.console.expect_prompt()
Пример #7
0
def kdb():
    kbuild.config(kgdb=True)
    kbuild.build()

    qemu = ktest.qemu()

    console = qemu.console
    console.expect_boot()
    console.expect_busybox()

    yield qemu

    qemu.close()


@pytest.mark.xfail(condition=(kbuild.get_arch() == 'mips'),
                   reason="Triggers breakpoint twice",
                   run=False)
@pytest.mark.xfail(condition=(kbuild.get_arch() == 'x86'),
                   reason="Triggers breakpoint twice",
                   run=False)
def test_BUG(kdb):
    '''
	Test how kdb reacts to a BUG()
	'''

    # Must use /bin/echo... if we use a shell built-in then the
    # kernel will kill off the shell when we resume
    kdb.console.sendline(
        '/bin/echo BUG > /sys/kernel/debug/provoke-crash/DIRECT')
Пример #8
0
		gdb.expect_prompt()
		kgdb.exit_gdb()

def test_info_target(kgdb):
	(console, gdb) = kgdb.enter_gdb()
	try:
		gdb.sendline('info target')
		gdb.expect('Debugging a target over a serial line')
	finally:
		gdb.expect_prompt()
		kgdb.exit_gdb()

# The failure on x86 has a reproduction rate of approximately 5%.
# It is rare but is frequent enough to affect suite reliability
# (and it causes a cascading failure so we will avoid runninng it)
@pytest.mark.xfail(condition = kbuild.get_arch() == 'x86', run = False,
                   reason = 'GDB reports packet errors')
def test_info_thread(kgdb):
	(console, gdb) = kgdb.enter_gdb()
	try:
		gdb.sendline('info thread')
		# One of the CPUs should be stopped in kgdb_breakpoint()
		gdb.expect('[(].*CPU.*[)][^\r\n]*kgdb_breakpoint')

		# Look for a few common thread names
		gdb.expect('[(]init[)]')
		gdb.expect('[(]kthreadd[)]')
		gdb.expect('[(]kworker/0:0[)]')

		# Check the shell process is in kgdb_breakpoint()
		gdb.expect('[(]sh[)][^\r\n]*kgdb_breakpoint')
Пример #9
0
import kbuild
import ktest
import pytest


@pytest.mark.xfail(condition=(kbuild.get_arch() == 'arm64'
                              and kbuild.get_version() < (4, 17)),
                   reason='Thread 10 has a PC of 0x0 (so cannot unwind)')
@pytest.mark.xfail(condition=(kbuild.get_arch() == 'x86'),
                   reason='inconsistent lock state')
def test_kgdb():
    '''High-level kgdb smoke test.

	Tour a number of kgdb features to prove that basic functionality
	if working OK.
	'''

    kbuild.config(kgdb=True)
    kbuild.build()

    qemu = ktest.qemu(second_uart=True, gdb=True, append='kgdbwait')
    console = qemu.console
    gdb = qemu.debug

    console.expect_boot(skip_late=True)
    console.expect('Waiting for connection from remote gdb...')
    gdb.connect_to_target()

    gdb.send('where\r')
    gdb.expect('kgdb_initial_breakpoint')
    gdb.expect(['init_kgdboc', 'configure_kgdboc'])
Пример #10
0
def qemu(kdb=True, append=None, gdb=False, gfx=False, interactive=False, second_uart=False):
	'''Create a qemu instance and provide pexpect channels to control it'''

	arch = kbuild.get_arch()
	host_arch = kbuild.get_host_arch()

	if arch == 'arm' or arch == 'arm64':
		tty = 'ttyAMA'
	else:
		tty = 'ttyS'

	if arch == 'arm64' or arch == 'riscv':
		second_uart = False

	cmdline = ''
	if gfx:
		cmdline += ' console=tty0'
	cmdline += ' console={}0,115200'.format(tty)
	if kdb:
		cmdline += ' kgdboc='
		if gfx:
			cmdline += 'kms,kbd,'
		if not second_uart:
			cmdline += '{}0'.format(tty)
		else:
			cmdline += '{}1'.format(tty)
	if gdb:
		cmdline += ' nokaslr'
	if arch == 'arm':
		# The versatile boot process no longer contains sneaky
		# ordering tricks to allow the console to come up without an
		# -EPROBE_DEFER. Putting it another way... we'll see timeouts
		# in several tests unless we have an earlycon.
		cmdline += ' earlycon=pl011,0x1c090000'
	if append:
		cmdline += ' ' + append

	# Heavily broken out so we can easily slot in support for other
	# architectures.
	if arch == 'arm':
		cmd = 'qemu-system-arm'
		cmd += ' -accel tcg,thread=multi '
		cmd += ' -M vexpress-a15 -cpu cortex-a15'
		cmd += ' -m 1G -smp 2'
		cmd += ' -kernel arch/arm/boot/zImage'
		cmd += ' -dtb arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dtb'
	elif arch == 'arm64':
		cmd = 'qemu-system-aarch64'
		if host_arch == 'arm64':
			cmd += ' -cpu host -M virt,gic_version=3,accel=kvm'
		else:
			cmd += ' -accel tcg,thread=multi '
			cmd += ' -M virt,gic_version=3 -cpu cortex-a57'
		cmd += ' -m 1G -smp 2'
		cmd += ' -kernel arch/arm64/boot/Image'
	elif arch == 'mips':
		cmd = 'qemu-system-mips64el'
		cmd += ' -accel tcg,thread=multi '
		cmd += ' -cpu I6400 -M malta'
		cmd += ' -m 1G -smp 2'
		cmd += ' -kernel vmlinux'
	elif arch == 'riscv':
		cmd = 'qemu-system-riscv64'
		cmd += ' -accel tcg,thread=multi'
		cmd += ' -machine virt'
		cmd += '  -m 1G -smp 2'
		cmd += ' -kernel arch/riscv/boot/Image'
	elif arch == 'x86':
		cmd = 'qemu-system-x86_64'
		if host_arch == 'x86':
			cmd += ' -enable-kvm'
		cmd += ' -m 1G -smp 2'
		cmd += ' -kernel arch/x86/boot/bzImage'
	else:
		assert False

	if not gfx:
		cmd += ' -nographic'
	if second_uart:
		cmd += ' -monitor none'
		cmd += ' -chardev stdio,id=mon,mux=on,signal=off -serial chardev:mon'
		cmd += ' -chardev socket,id=ttyS1,path=ttyS1.sock,server,nowait'
		cmd += ' -serial chardev:ttyS1'
	elif gdb:
		cmd += ' -S -chardev pty,id=ttyS0 -serial chardev:ttyS0'
	else:
		cmd += ' -monitor none'
		cmd += ' -chardev stdio,id=mon,mux=on,signal=off -serial chardev:mon'

	cmd += ' -initrd rootfs.cpio.gz'
	cmd += ' -append "{}"'.format(cmdline)

	if gdb:
		gdbcmd = kbuild.get_cross_compile('gdb')
		gdbcmd += ' vmlinux'
		gdbcmd += ' -ex "set pagination 0"'

	if interactive:
		if gdb:
			gdbcmd += ' -ex "target extended-remote |' + \
					'socat - UNIX:ttyS1.sock"'
			print ('\n>>> (cd {}; {})\n'.format(
					kbuild.get_kdir(), gdbcmd))

		print('+| ' + cmd)
		time.sleep(5)
		os.system(cmd)
		return None

	print('+| ' + cmd)
	qemu = pexpect.spawn(cmd, encoding='utf-8', logfile=sys.stdout)

	if gdb:
		print('+| ' + gdbcmd)
		gdb = pexpect.spawn(gdbcmd,
				encoding='utf-8', logfile=sys.stdout)
	else:
		gdb = None

	if gdb and not second_uart:
		monitor = qemu
		monitor.expect('char device redirected to (/dev/pts/[0-9]*) .label')
		uart_pty = monitor.match.group(1)

		dmx = pexpect.spawn(f'kdmx -p {uart_pty}', encoding='utf-8', logfile=sys.stdout)
		dmx.expect('(/dev/pts/[0-9]*) is slave pty for terminal emulator')
		console_pty = dmx.match.group(1)
		dmx.expect('(/dev/pts/[0-9]*) is slave pty for gdb')
		gdb_pty = dmx.match.group(1)
		gdb.connection = gdb_pty;
		print(f'Demuxing from {uart_pty} to {console_pty}^{gdb_pty}')

		# Start picocom and wait for it to be ready. It *must* be ready before
		# we (cont)inue in the qemu monitor or we will miss the initial boot
		# messages. Sadly it appears that, even though picocom has opened all
		# the file handles when it says "Terminal ready" the connection isn't
		# fully established until picocom calls select() in its event loop.
		# Enable/disable local echo in order to guarantee we get that far.
		console = pexpect.spawn(f'picocom {console_pty}', encoding='utf-8', logfile=sys.stdout)
		console.expect('picocom')
		console.expect('Terminal ready')
		console.send('\x01\x03\x01\03')
		console.expect('local echo.*no')
		time.sleep(1)

		# Attach the kdmx process to the monitor (otherwise it will be
		# closed when the function exits.
		monitor.dmx = dmx

		# Set everything running
		monitor.expect('[(]qemu[)]')
		monitor.sendline('cont')
		monitor.expect('[(]qemu[)]')

		return ConsoleWrapper(console, gdb, monitor)
	else:
		if gdb:
			gdb.connection = '|socat - UNIX:ttyS1.sock'
		return ConsoleWrapper(qemu, gdb)
Пример #11
0
import kbuild
import ktest
import pytest


@pytest.mark.xfail(condition=kbuild.get_version() < (5, 8),
                   run=False,
                   reason='Not implemented until 5.8-rc1')
@pytest.mark.skipif(kbuild.get_arch() not in ('arm', 'arm64', 'x86'),
                    reason='earlycon not configured for this arch')
def test_earlycon():
    kbuild.config(kgdb=True)
    kbuild.build()

    # Handle platforms that cannot auto-configure the earlycon
    arch = kbuild.get_arch()
    if 'x86' == arch:
        earlycon = "earlycon=uart8250,io,0x3f8"
    elif 'arm' == arch:
        earlycon = "earlycon=pl011,0x1c090000"
    else:
        earlycon = "earlycon"

    qemu = ktest.qemu(append=f'{earlycon} kgdboc_earlycon kgdbwait')
    console = qemu.console

    def expect_and_page(c, needle):
        choices = [needle, 'more>']

        choice = c.expect(choices)
        while choice == 1: