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: 56434 Delivered-To: patch@linaro.org Received: by 10.112.155.196 with SMTP id vy4csp510229lbb; Thu, 12 Nov 2015 08:22:57 -0800 (PST) X-Received: by 10.31.134.79 with SMTP id i76mr4366966vkd.72.1447345377204; Thu, 12 Nov 2015 08:22:57 -0800 (PST) Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id 72si3151779vkj.16.2015.11.12.08.22.56 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Thu, 12 Nov 2015 08:22:57 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org; dkim=fail header.i=@linaro_org.20150623.gappssmtp.com Received: from localhost ([::1]:47664 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZwueG-0002Xh-Lk for patch@linaro.org; Thu, 12 Nov 2015 11:22:56 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52191) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Zwuci-0000XM-6A for qemu-devel@nongnu.org; Thu, 12 Nov 2015 11:21:21 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Zwucg-0003NG-0i for qemu-devel@nongnu.org; Thu, 12 Nov 2015 11:21:20 -0500 Received: from mail-wm0-x235.google.com ([2a00:1450:400c:c09::235]:36686) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Zwucf-0003MN-KX for qemu-devel@nongnu.org; Thu, 12 Nov 2015 11:21:17 -0500 Received: by wmww144 with SMTP id w144so207576023wmw.1 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=DIKiIc7Q3i29Eraglb+wdHO/qgJR+ZXVX2JTVDhR+A6YLabPxGvcniTq65pKdlbZvw RAt3zl/AkEYKHTP3Y1IWZkXtxMySRHCQDmtpuDWSR4WUfTJMmv3t7UINpFATnhQiJ/LE 3ZrR83i/kATBnhlqqH6BAMOm4nSuo8Iev26gDtJ/5BKh5TCiT7Xg1UnC3468cqhmMlVN qjyL3s7yw603eFd0u/UFNHonSvbeM1QHzYJxXMif9Cw5DoJw/A80tg8ozyi8feEyEP+7 54Xvc1mVSV39/UNvC+mRi9RoWVQNRwsOdBJS8BvX+pjmOJQaEHlU36TU6e68vjgSwmM/ tqDA== X-Gm-Message-State: ALoCoQm0inG8qE5er0+oAwONKh20Y1vctOkBnUGt2LIqjHN/s8iaXM0uVGbKbTz2QG+AarCz+WO9 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 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-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c09::235 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 Subject: [Qemu-devel] [PATCH v9 6/6] tests/guest-debug: introduce basic gdbstub tests X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: qemu-devel-bounces+patch=linaro.org@nongnu.org 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 -- 2.6.3 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)