From patchwork Thu Nov 12 16:20:51 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Alex_Benn=C3=A9e?= X-Patchwork-Id: 7603531 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 04006BF90C for ; Thu, 12 Nov 2015 16:25:13 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AE04D20816 for ; Thu, 12 Nov 2015 16:25:08 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 432FE2081B for ; Thu, 12 Nov 2015 16:25:06 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZwueT-00074K-Tx; Thu, 12 Nov 2015 16:23:09 +0000 Received: from mail-wm0-x234.google.com ([2a00:1450:400c:c09::234]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Zwud0-0005zl-J8 for linux-arm-kernel@lists.infradead.org; Thu, 12 Nov 2015 16:21:44 +0000 Received: by wmec201 with SMTP id c201so41251724wme.0 for ; Thu, 12 Nov 2015 08:21:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro_org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=Ej8SiZK/pzRpsbBpt+k0/5kKW9hVHfS1VznWf6aRRgQ=; b=o71Bg8q5g8P+PIVmgcNS7pmTUjMpb9yoXLU/aSi050tSgedD2bQq/Hmihg3qg7cBoB eH3ogPYA0GkVJQbFJooLTisSHzqZdlKl2wQCxI/5RBNV6S7UMIj4QAT5h+h4oy0Bf/q8 2IEu1k7aLJWF3JqMhyUK9aD3ZzVIXsseBecOdIpDBJeBWDHSN2cBPOo9yNYD3GNm3x4e e1Mna6P1ajuavNpLB/2BsE+yj2UY700GwWkBu6TbASTtaYjLDoxXj8UyJ0vesxeDmq+s 1pz2ZZb5iPRdPdnGPVEIU0LwSEPi/J6dF8Oq/mcOc2e8MIFdJUIH1v36kBsRRcr+y2TD xVDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-type:content-transfer-encoding; bh=Ej8SiZK/pzRpsbBpt+k0/5kKW9hVHfS1VznWf6aRRgQ=; b=JvBXU6ANmT1h4VD3A+d0g1WYrxyh7GBbwDSCejRqbuoVx4bl0b9cwiz2pvN8coJZvd xjE8L8liozs8a+lfcjhMOsnBYnD0Pln5r+6/l5awl13SZI3xySwXmKKzIPpNb1xB+DEs hyZxuJXSzFbQDb9/EkVcz7neBWEOFAmoEpm1EaFRO8o3+MQIq17CkEC9JZSX6CimOlen pt2Wv5YfbSIs5iK+2CxwAghgHmFUy9tYLdyqGD1acUshXHL9jj59Y1u0R3XlN1Z1oJtP TkzDJUVH4JgFVF3BEWJiLarJ1+/J7dpqVi7BLEapcdxp7TlhVuZXQTZaiY2fSlc/pDsx Tj6g== X-Gm-Message-State: ALoCoQlrVuaygV7AyWMlS+rAj9qKd04DYAqq/h3BKBIyi/fWgn+AUuH7LDH02vktao5nzmHza46X X-Received: by 10.28.19.65 with SMTP id 62mr17850199wmt.35.1447345276996; Thu, 12 Nov 2015 08:21:16 -0800 (PST) Received: from zen.linaro.local ([81.128.185.34]) by smtp.gmail.com with ESMTPSA id 71sm15784942wmm.24.2015.11.12.08.21.14 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 Nov 2015 08:21:16 -0800 (PST) Received: from zen.linaroharston (localhost [127.0.0.1]) by zen.linaro.local (Postfix) with ESMTP id E56523E0682; Thu, 12 Nov 2015 16:21:12 +0000 (GMT) From: =?UTF-8?q?Alex=20Benn=C3=A9e?= To: qemu-devel@nongnu.org, qemu-arm@nongnu.org, peter.maydell@linaro.org, christoffer.dall@linaro.org, zhichao.huang@linaro.org Subject: [PATCH v9 6/6] tests/guest-debug: introduce basic gdbstub tests Date: Thu, 12 Nov 2015 16:20:51 +0000 Message-Id: <1447345251-22625-7-git-send-email-alex.bennee@linaro.org> X-Mailer: git-send-email 2.6.3 In-Reply-To: <1447345251-22625-1-git-send-email-alex.bennee@linaro.org> References: <1447345251-22625-1-git-send-email-alex.bennee@linaro.org> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20151112_082138_869162_F5B5F28D X-CRM114-Status: GOOD ( 19.52 ) X-Spam-Score: -2.6 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?UTF-8?q?Alex=20Benn=C3=A9e?= , kvm@vger.kernel.org, marc.zyngier@arm.com, =?UTF-8?q?Alex=20Benn=C3=A9e?= , kvmarm@lists.cs.columbia.edu, linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Alex Bennée The aim of these tests is to combine with an appropriate kernel image (with symbol-file vmlinux) and check it behaves as it should. Given a kernel it checks: - single step - software breakpoint - hardware breakpoint - access, read and write watchpoints On success it returns 0 to the calling process. I've not plumbed this into the "make check" logic though as we need a solution for providing non-host binaries to the tests. However the test is structured to work with pretty much any Linux kernel image as it uses the basic kernel_init code which is common across architectures. Signed-off-by: Alex Bennée --- tests/guest-debug/test-gdbstub.py | 171 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 tests/guest-debug/test-gdbstub.py diff --git a/tests/guest-debug/test-gdbstub.py b/tests/guest-debug/test-gdbstub.py new file mode 100644 index 0000000..aa53567 --- /dev/null +++ b/tests/guest-debug/test-gdbstub.py @@ -0,0 +1,171 @@ +# +# This script needs to be run on startup +# qemu -kernel ${KERNEL} -s -S +# and then: +# gdb ${KERNEL}.vmlinux -x ${QEMU_SRC}/tests/guest-debug/test-gdbstub.py + +import gdb + +failcount = 0 + +def report(cond, msg): + "Report success/fail of test" + if cond: + print "PASS: %s" % (msg) + else: + print "FAIL: %s" % (msg) + failcount += 1 + +def check_step(): + "Step an instruction, check it moved." + start_pc = gdb.parse_and_eval('$pc') + gdb.execute("si") + end_pc = gdb.parse_and_eval('$pc') + + return not (start_pc == end_pc) + + +def check_break(sym_name): + "Setup breakpoint, continue and check we stopped." + sym, ok = gdb.lookup_symbol(sym_name) + bp = gdb.Breakpoint(sym_name) + + gdb.execute("c") + + # hopefully we came back + end_pc = gdb.parse_and_eval('$pc') + print "%s == %s %d" % (end_pc, sym.value(), bp.hit_count) + bp.delete() + + # can we test we hit bp? + return end_pc == sym.value() + + +# We need to do hbreak manually as the python interface doesn't export it +def check_hbreak(sym_name): + "Setup hardware breakpoint, continue and check we stopped." + sym, ok = gdb.lookup_symbol(sym_name) + gdb.execute("hbreak %s" % (sym_name)) + gdb.execute("c") + + # hopefully we came back + end_pc = gdb.parse_and_eval('$pc') + print "%s == %s" % (end_pc, sym.value()) + + if end_pc == sym.value(): + gdb.execute("d 1") + return True + else: + return False + + +class WatchPoint(gdb.Breakpoint): + + def get_wpstr(self, sym_name): + "Setup sym and wp_str for given symbol." + self.sym, ok = gdb.lookup_symbol(sym_name) + wp_addr = gdb.parse_and_eval(sym_name).address + self.wp_str = '*(%(type)s)(&%(address)s)' % dict( + type = wp_addr.type, address = sym_name) + + return(self.wp_str) + + def __init__(self, sym_name, type): + wp_str = self.get_wpstr(sym_name) + super(WatchPoint, self).__init__(wp_str, gdb.BP_WATCHPOINT, type) + + def stop(self): + end_pc = gdb.parse_and_eval('$pc') + print "HIT WP @ %s" % (end_pc) + return True + + +def do_one_watch(sym, wtype, text): + + wp = WatchPoint(sym, wtype) + gdb.execute("c") + report_str = "%s for %s (%s)" % (text, sym, wp.sym.value()) + + if wp.hit_count > 0: + report(True, report_str) + wp.delete() + else: + report(False, report_str) + + +def check_watches(sym_name): + "Watch a symbol for any access." + + # Should hit for any read + do_one_watch(sym_name, gdb.WP_ACCESS, "awatch") + + # Again should hit for reads + do_one_watch(sym_name, gdb.WP_READ, "rwatch") + + # Finally when it is written + do_one_watch(sym_name, gdb.WP_WRITE, "watch") + + +class CatchBreakpoint(gdb.Breakpoint): + def __init__(self, sym_name): + super(CatchBreakpoint, self).__init__(sym_name) + self.sym, ok = gdb.lookup_symbol(sym_name) + + def stop(self): + end_pc = gdb.parse_and_eval ('$pc') + print "CB: %s == %s" % (end_pc, self.sym.value()) + if end_pc == sym.value(): + report(False, "Hit final catchpoint") + + +def run_test(): + "Run throught the tests one by one" + + print "Checking we can step the first few instructions" + step_ok = 0 + for i in xrange(3): + if check_step(): + step_ok += 1 + + report(step_ok == 3, "single step in boot code") + + print "Checking HW breakpoint works" + break_ok = check_hbreak("kernel_init") + report(break_ok, "hbreak @ kernel_init") + + # Can't set this up until we are in the kernel proper + # if we make it to run_init_process we've over-run and + # one of the tests failed + print "Setup catch-all for run_init_process" + cbp = CatchBreakpoint("run_init_process") + cpb2 = CatchBreakpoint("try_to_run_init_process") + + print "Checking Normal breakpoint works" + break_ok = check_break("wait_for_completion") + report(break_ok, "break @ wait_for_completion") + + print "Checking watchpoint works" + check_watches("system_state") + +# +# This runs as the script it sourced (via -x) +# + +try: + print "Connecting to remote" + gdb.execute("target remote localhost:1234") + + # These are not very useful in scripts + gdb.execute("set pagination off") + gdb.execute("set confirm off") + + # Run the actual tests + run_test() + +except: + print "GDB Exception while running test" + failcount += 1 + +# Finally kill the inferior and exit gdb with a count of failures +gdb.execute("kill") +exit(failcount)