From patchwork Wed Jun 20 05:34:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Popple X-Patchwork-Id: 931955 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 419YS11Vq1z9s4n for ; Wed, 20 Jun 2018 15:34:41 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 419YS100hrzF0wb for ; Wed, 20 Jun 2018 15:34:41 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Received: from ozlabs.org (ozlabs.org [IPv6:2401:3900:2:1::2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 419YRY3c9pzF0wb for ; Wed, 20 Jun 2018 15:34:17 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from authenticated.ozlabs.org (localhost [127.0.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPSA id 419YRY0w34z9s7F; Wed, 20 Jun 2018 15:34:17 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au From: Alistair Popple To: pdbg@lists.ozlabs.org Date: Wed, 20 Jun 2018 15:34:02 +1000 Message-Id: <20180620053409.14538-2-alistair@popple.id.au> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180620053409.14538-1-alistair@popple.id.au> References: <20180620053409.14538-1-alistair@popple.id.au> Subject: [Pdbg] [PATCH 1/8] ccan: Add cppmagic X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" A couple of arguably useful C preprocessor abuses. License is BSD-MIT. Signed-off-by: Alistair Popple --- ccan/cppmagic/LICENSE | 1 + ccan/cppmagic/_info | 30 ++++++++ ccan/cppmagic/cppmagic.h | 191 +++++++++++++++++++++++++++++++++++++++++++++++ ccan/cppmagic/test/run.c | 92 +++++++++++++++++++++++ 4 files changed, 314 insertions(+) create mode 120000 ccan/cppmagic/LICENSE create mode 100644 ccan/cppmagic/_info create mode 100644 ccan/cppmagic/cppmagic.h create mode 100644 ccan/cppmagic/test/run.c diff --git a/ccan/cppmagic/LICENSE b/ccan/cppmagic/LICENSE new file mode 120000 index 0000000..2354d12 --- /dev/null +++ b/ccan/cppmagic/LICENSE @@ -0,0 +1 @@ +../../licenses/BSD-MIT \ No newline at end of file diff --git a/ccan/cppmagic/_info b/ccan/cppmagic/_info new file mode 100644 index 0000000..aad394b --- /dev/null +++ b/ccan/cppmagic/_info @@ -0,0 +1,30 @@ +#include "config.h" +#include +#include + +/** + * cppmagic - Abuse of the C preprocessor + * + * This contains a bunch of fancy macro techniques such as + * preprocessor-time evaluated conditionals and (quasi) recursion and + * iteration. + * + * It's based on these articles: + * - http://jhnet.co.uk/articles/cpp_magic + * - https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms + * and code from the Boost C++ library. + * + * License: BSD-MIT + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + return 0; + } + + return 1; +} diff --git a/ccan/cppmagic/cppmagic.h b/ccan/cppmagic/cppmagic.h new file mode 100644 index 0000000..f1f6868 --- /dev/null +++ b/ccan/cppmagic/cppmagic.h @@ -0,0 +1,191 @@ +/* MIT (BSD) license - see LICENSE file for details */ +#ifndef CCAN_CPPMAGIC_H +#define CCAN_CPPMAGIC_H + +/** + * CPPMAGIC_NOTHING - expands to nothing + */ +#define CPPMAGIC_NOTHING() + +/** + * CPPMAGIC_STRINGIFY - convert arguments to a string literal + */ +#define _CPPMAGIC_STRINGIFY(...) #__VA_ARGS__ +#define CPPMAGIC_STRINGIFY(...) _CPPMAGIC_STRINGIFY(__VA_ARGS__) + +/** + * CPPMAGIC_GLUE2 - glue arguments together + * + * CPPMAGIC_GLUE2(@a_, @b_) + * expands to the expansion of @a_ followed immediately + * (combining tokens) by the expansion of @b_ + */ +#define _CPPMAGIC_GLUE2(a_, b_) a_##b_ +#define CPPMAGIC_GLUE2(a_, b_) _CPPMAGIC_GLUE2(a_, b_) + +/** + * CPPMAGIC_1ST - return 1st argument + * + * CPPMAGIC_1ST(@a_, ...) + * expands to the expansion of @a_ + */ +#define CPPMAGIC_1ST(a_, ...) a_ + +/** + * CPPMAGIC_2ND - return 2nd argument + * + * CPPMAGIC_2ST(@a_, @b_, ...) + * expands to the expansion of @b_ + */ +#define CPPMAGIC_2ND(a_, b_, ...) b_ + +/** + * CPPMAGIC_ISZERO - is argument '0' + * + * CPPMAGIC_ISZERO(@a) + * expands to '1' if @a is '0', otherwise expands to '0'. + */ +#define _CPPMAGIC_ISPROBE(...) CPPMAGIC_2ND(__VA_ARGS__, 0) +#define _CPPMAGIC_PROBE() $, 1 +#define _CPPMAGIC_ISZERO_0 _CPPMAGIC_PROBE() +#define CPPMAGIC_ISZERO(a_) \ + _CPPMAGIC_ISPROBE(CPPMAGIC_GLUE2(_CPPMAGIC_ISZERO_, a_)) + +/** + * CPPMAGIC_NONZERO - is argument not '0' + * + * CPPMAGIC_NONZERO(@a) + * expands to '0' if @a is '0', otherwise expands to '1'. + */ +#define CPPMAGIC_NONZERO(a_) CPPMAGIC_ISZERO(CPPMAGIC_ISZERO(a_)) + +/** + * CPPMAGIC_NONEMPTY - does the macro have any arguments? + * + * CPPMAGIC_NONEMPTY() + * expands to '0' + * CPPMAGIC_NONEMPTY(@a) + * CPPMAGIC_NONEMPTY(@a, ...) + * expand to '1' + */ +#define _CPPMAGIC_EOA() 0 +#define CPPMAGIC_NONEMPTY(...) \ + CPPMAGIC_NONZERO(CPPMAGIC_1ST(_CPPMAGIC_EOA __VA_ARGS__)()) + +/** + * CPPMAGIC_ISEMPTY - does the macro have no arguments? + * + * CPPMAGIC_ISEMPTY() + * expands to '1' + * CPPMAGIC_ISEMPTY(@a) + * CPPMAGIC_ISEMPTY(@a, ...) + * expand to '0' + */ +#define CPPMAGIC_ISEMPTY(...) \ + CPPMAGIC_ISZERO(CPPMAGIC_NONEMPTY(__VA_ARGS__)) + +/* + * CPPMAGIC_IFELSE - preprocessor conditional + * + * CPPMAGIC_IFELSE(@cond)(@if)(@else) + * expands to @else if @cond is '0', otherwise expands to @if + */ +#define _CPPMAGIC_IF_0(...) _CPPMAGIC_IF_0_ELSE +#define _CPPMAGIC_IF_1(...) __VA_ARGS__ _CPPMAGIC_IF_1_ELSE +#define _CPPMAGIC_IF_0_ELSE(...) __VA_ARGS__ +#define _CPPMAGIC_IF_1_ELSE(...) +#define _CPPMAGIC_IFELSE(cond_) CPPMAGIC_GLUE2(_CPPMAGIC_IF_, cond_) +#define CPPMAGIC_IFELSE(cond_) \ + _CPPMAGIC_IFELSE(CPPMAGIC_NONZERO(cond_)) + +/** + * CPPMAGIC_EVAL - force multiple expansion passes + * + * Forces macros in the arguments to be expanded repeatedly (up to + * 1024 times) even when CPP would usually stop expanding. + */ +#define CPPMAGIC_EVAL1(...) __VA_ARGS__ +#define CPPMAGIC_EVAL2(...) \ + CPPMAGIC_EVAL1(CPPMAGIC_EVAL1(__VA_ARGS__)) +#define CPPMAGIC_EVAL4(...) \ + CPPMAGIC_EVAL2(CPPMAGIC_EVAL2(__VA_ARGS__)) +#define CPPMAGIC_EVAL8(...) \ + CPPMAGIC_EVAL4(CPPMAGIC_EVAL4(__VA_ARGS__)) +#define CPPMAGIC_EVAL16(...) \ + CPPMAGIC_EVAL8(CPPMAGIC_EVAL8(__VA_ARGS__)) +#define CPPMAGIC_EVAL32(...) \ + CPPMAGIC_EVAL16(CPPMAGIC_EVAL16(__VA_ARGS__)) +#define CPPMAGIC_EVAL64(...) \ + CPPMAGIC_EVAL32(CPPMAGIC_EVAL32(__VA_ARGS__)) +#define CPPMAGIC_EVAL128(...) \ + CPPMAGIC_EVAL64(CPPMAGIC_EVAL64(__VA_ARGS__)) +#define CPPMAGIC_EVAL256(...) \ + CPPMAGIC_EVAL128(CPPMAGIC_EVAL128(__VA_ARGS__)) +#define CPPMAGIC_EVAL512(...) \ + CPPMAGIC_EVAL256(CPPMAGIC_EVAL256(__VA_ARGS__)) +#define CPPMAGIC_EVAL1024(...) \ + CPPMAGIC_EVAL512(CPPMAGIC_EVAL512(__VA_ARGS__)) +#define CPPMAGIC_EVAL(...) CPPMAGIC_EVAL1024(__VA_ARGS__) + +/** + * CPPMAGIC_DEFER1, CPPMAGIC_DEFER2 - defer expansion + */ +#define CPPMAGIC_DEFER1(a_) a_ CPPMAGIC_NOTHING() +#define CPPMAGIC_DEFER2(a_) a_ CPPMAGIC_NOTHING CPPMAGIC_NOTHING()() + +/** + * CPPMAGIC_MAP - iterate another macro across arguments + * @m: name of a one argument macro + * + * CPPMAGIC_MAP(@m, @a1, @a2, ... @an) + * expands to the expansion of @m(@a1) , @m(@a2) , ... , @m(@an) + */ +#define _CPPMAGIC_MAP_() _CPPMAGIC_MAP +#define _CPPMAGIC_MAP(m_, a_, ...) \ + m_(a_) \ + CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \ + (, CPPMAGIC_DEFER2(_CPPMAGIC_MAP_)()(m_, __VA_ARGS__)) \ + () +#define CPPMAGIC_MAP(m_, ...) \ + CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \ + (CPPMAGIC_EVAL(_CPPMAGIC_MAP(m_, __VA_ARGS__))) \ + () + +/** + * CPPMAGIC_2MAP - iterate another macro across pairs of arguments + * @m: name of a two argument macro + * + * CPPMAGIC_2MAP(@m, @a1, @b1, @a2, @b2, ..., @an, @bn) + * expands to the expansion of + * @m(@a1, @b1) , @m(@a2, @b2) , ... , @m(@an, @bn) + */ +#define _CPPMAGIC_2MAP_() _CPPMAGIC_2MAP +#define _CPPMAGIC_2MAP(m_, a_, b_, ...) \ + m_(a_, b_) \ + CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \ + (, CPPMAGIC_DEFER2(_CPPMAGIC_2MAP_)()(m_, __VA_ARGS__)) \ + () +#define CPPMAGIC_2MAP(m_, ...) \ + CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \ + (CPPMAGIC_EVAL(_CPPMAGIC_2MAP(m_, __VA_ARGS__))) \ + () + +/** + * CPPMAGIC_JOIN - separate arguments with given delimiter + * @d: delimiter + * + * CPPMAGIC_JOIN(@d, @a1, @a2, ..., @an) + * expands to the expansion of @a1 @d @a2 @d ... @d @an + */ +#define _CPPMAGIC_JOIN_() _CPPMAGIC_JOIN +#define _CPPMAGIC_JOIN(d_, a_, ...) \ + a_ \ + CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \ + (d_ CPPMAGIC_DEFER2(_CPPMAGIC_JOIN_)()(d_, __VA_ARGS__)) \ + () +#define CPPMAGIC_JOIN(d_, ...) \ + CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \ + (CPPMAGIC_EVAL(_CPPMAGIC_JOIN(d_, __VA_ARGS__))) \ + () + +#endif /* CCAN_CPPMAGIC_H */ diff --git a/ccan/cppmagic/test/run.c b/ccan/cppmagic/test/run.c new file mode 100644 index 0000000..7c0aa7f --- /dev/null +++ b/ccan/cppmagic/test/run.c @@ -0,0 +1,92 @@ +#include "config.h" + +#include + +#include +#include + +static inline void check1(const char *orig, const char *expand, + const char *match) +{ + ok(strcmp(expand, match) == 0, + "%s => %s : %s", orig, expand, match); +} + +#define CHECK1(orig, match) \ + check1(#orig, CPPMAGIC_STRINGIFY(orig), match) + +#define TESTRECURSE() R CPPMAGIC_DEFER1(_TESTRECURSE) ()() +#define _TESTRECURSE() TESTRECURSE + +#define TESTMAP1(x) <> + +#define TESTMAP2(x) [[ x +#define TESTMAP3(x) x ]] + +#define TEST2MAP(x, y) x ** y + +int main(void) +{ + plan_tests(42); + + CHECK1(CPPMAGIC_NOTHING(), ""); + CHECK1(CPPMAGIC_GLUE2(a, b), "ab"); + + CHECK1(CPPMAGIC_1ST(a), "a"); + CHECK1(CPPMAGIC_1ST(a, b), "a"); + CHECK1(CPPMAGIC_1ST(a, b, c), "a"); + + CHECK1(CPPMAGIC_2ND(a, b), "b"); + CHECK1(CPPMAGIC_2ND(a, b, c), "b"); + + CHECK1(CPPMAGIC_ISZERO(0), "1"); + CHECK1(CPPMAGIC_ISZERO(1), "0"); + CHECK1(CPPMAGIC_ISZERO(123), "0"); + CHECK1(CPPMAGIC_ISZERO(abc), "0"); + + CHECK1(CPPMAGIC_NONZERO(0), "0"); + CHECK1(CPPMAGIC_NONZERO(1), "1"); + CHECK1(CPPMAGIC_NONZERO(123), "1"); + CHECK1(CPPMAGIC_NONZERO(abc), "1"); + + CHECK1(CPPMAGIC_NONEMPTY(), "0"); + CHECK1(CPPMAGIC_NONEMPTY(0), "1"); + CHECK1(CPPMAGIC_NONEMPTY(a, b, c), "1"); + + CHECK1(CPPMAGIC_ISEMPTY(), "1"); + CHECK1(CPPMAGIC_ISEMPTY(0), "0"); + CHECK1(CPPMAGIC_ISEMPTY(a, b, c), "0"); + + CHECK1(CPPMAGIC_IFELSE(0)(abc)(def), "def"); + CHECK1(CPPMAGIC_IFELSE(1)(abc)(def), "abc"); + CHECK1(CPPMAGIC_IFELSE(not zero)(abc)(def), "abc"); + + CHECK1(TESTRECURSE(), "R R _TESTRECURSE ()()"); + CHECK1(CPPMAGIC_EVAL1(TESTRECURSE()), "R R R _TESTRECURSE ()()"); + CHECK1(CPPMAGIC_EVAL2(TESTRECURSE()), "R R R R R _TESTRECURSE ()()"); + + CHECK1(CPPMAGIC_MAP(TESTMAP1), ""); + CHECK1(CPPMAGIC_MAP(TESTMAP1, a), "<>"); + CHECK1(CPPMAGIC_MAP(TESTMAP1, a, b), "<> , <>"); + CHECK1(CPPMAGIC_MAP(TESTMAP1, a, b, c), "<> , <> , <>"); + + CHECK1(CPPMAGIC_2MAP(TEST2MAP), ""); + CHECK1(CPPMAGIC_2MAP(TEST2MAP, a, 1), "a ** 1"); + CHECK1(CPPMAGIC_2MAP(TEST2MAP, a, 1, b, 2), "a ** 1 , b ** 2"); + + CHECK1(CPPMAGIC_JOIN(;), ""); + CHECK1(CPPMAGIC_JOIN(;, a), "a"); + CHECK1(CPPMAGIC_JOIN(;, a, b), "a ; b"); + CHECK1(CPPMAGIC_JOIN(;, a, b, c), "a ; b ; c"); + + /* Check chaining of MAPs */ + CHECK1(CPPMAGIC_MAP(TESTMAP2, CPPMAGIC_MAP(TESTMAP3)), ""); + CHECK1(CPPMAGIC_MAP(TESTMAP2, CPPMAGIC_MAP(TESTMAP3, a)), "[[ a ]]"); + CHECK1(CPPMAGIC_MAP(TESTMAP2, CPPMAGIC_MAP(TESTMAP3, a, b)), + "[[ a ]] , [[ b ]]"); + CHECK1(CPPMAGIC_MAP(TESTMAP2, CPPMAGIC_MAP(TESTMAP3, a, b, c)), + "[[ a ]] , [[ b ]] , [[ c ]]"); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} From patchwork Wed Jun 20 05:34:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Popple X-Patchwork-Id: 931956 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 419YS30XTSz9s7F for ; Wed, 20 Jun 2018 15:34:43 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 419YS25yDwzF0xF for ; Wed, 20 Jun 2018 15:34:42 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Received: from ozlabs.org (ozlabs.org [IPv6:2401:3900:2:1::2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 419YRY626tzF0wf for ; Wed, 20 Jun 2018 15:34:17 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from authenticated.ozlabs.org (localhost [127.0.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPSA id 419YRY3V2tz9s4n; Wed, 20 Jun 2018 15:34:17 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au From: Alistair Popple To: pdbg@lists.ozlabs.org Date: Wed, 20 Jun 2018 15:34:03 +1000 Message-Id: <20180620053409.14538-3-alistair@popple.id.au> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180620053409.14538-1-alistair@popple.id.au> References: <20180620053409.14538-1-alistair@popple.id.au> Subject: [Pdbg] [PATCH 2/8] ccan/cppmagic: Fix NONEMPTY macro X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" The original implementation of non-empty will fail to compile if passed an argument of the form 'CPPMAGIC_NONEMPTY((...))'. Add a check for parentheses and return true if passed. Signed-off-by: Alistair Popple --- ccan/cppmagic/cppmagic.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ccan/cppmagic/cppmagic.h b/ccan/cppmagic/cppmagic.h index f1f6868..587fe4e 100644 --- a/ccan/cppmagic/cppmagic.h +++ b/ccan/cppmagic/cppmagic.h @@ -68,9 +68,15 @@ * CPPMAGIC_NONEMPTY(@a, ...) * expand to '1' */ -#define _CPPMAGIC_EOA() 0 +#define CHECK_N(x, n, ...) n +#define CHECK(...) CHECK_N(__VA_ARGS__, , ) +#define PROBE(x) x, 1, +#define IS_PAREN(x, ...) CHECK(IS_PAREN_PROBE x) +#define IS_PAREN_PROBE(...) PROBE(~) + +#define _CPPMAGIC_EOA(a_, ...) 0 #define CPPMAGIC_NONEMPTY(...) \ - CPPMAGIC_NONZERO(CPPMAGIC_1ST(_CPPMAGIC_EOA __VA_ARGS__)()) + CPPMAGIC_NONZERO(CPPMAGIC_1ST(_CPPMAGIC_EOA IS_PAREN(__VA_ARGS__) __VA_ARGS__)()) /** * CPPMAGIC_ISEMPTY - does the macro have no arguments? From patchwork Wed Jun 20 05:34:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Popple X-Patchwork-Id: 931957 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 419YS60czJz9s4w for ; Wed, 20 Jun 2018 15:34:46 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 419YS55vKkzF0x4 for ; Wed, 20 Jun 2018 15:34:45 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Received: from ozlabs.org (bilbo.ozlabs.org [203.11.71.1]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 419YRZ3V4jzF0wj for ; Wed, 20 Jun 2018 15:34:18 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from authenticated.ozlabs.org (localhost [127.0.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPSA id 419YRY5t6kz9s7X; Wed, 20 Jun 2018 15:34:17 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au From: Alistair Popple To: pdbg@lists.ozlabs.org Date: Wed, 20 Jun 2018 15:34:04 +1000 Message-Id: <20180620053409.14538-4-alistair@popple.id.au> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180620053409.14538-1-alistair@popple.id.au> References: <20180620053409.14538-1-alistair@popple.id.au> Subject: [Pdbg] [PATCH 3/8] ccan/cppmagic: Add CPPMAGIC_INC(x) macro X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" The original ccan module does not include a macro to increment numbers. Add one which will increment upto 32 which is enough for our usage. Signed-off-by: Alistair Popple --- ccan/cppmagic/cppmagic.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/ccan/cppmagic/cppmagic.h b/ccan/cppmagic/cppmagic.h index 587fe4e..ffd5848 100644 --- a/ccan/cppmagic/cppmagic.h +++ b/ccan/cppmagic/cppmagic.h @@ -194,4 +194,45 @@ (CPPMAGIC_EVAL(_CPPMAGIC_JOIN(d_, __VA_ARGS__))) \ () +/** + * CPPMAGIC_INC - increment the argument + * @d: integer between 0 and 32 to increment + * + * Increments the integer to a maximum of 32 and saturates + */ +#define CPPMAGIC_INC(d_) CPPMAGIC_GLUE2(_CPPMAGIC_INC_, d_) +#define _CPPMAGIC_INC_0 1 +#define _CPPMAGIC_INC_1 2 +#define _CPPMAGIC_INC_2 3 +#define _CPPMAGIC_INC_3 4 +#define _CPPMAGIC_INC_4 5 +#define _CPPMAGIC_INC_5 6 +#define _CPPMAGIC_INC_6 7 +#define _CPPMAGIC_INC_7 8 +#define _CPPMAGIC_INC_8 9 +#define _CPPMAGIC_INC_9 10 +#define _CPPMAGIC_INC_10 11 +#define _CPPMAGIC_INC_11 12 +#define _CPPMAGIC_INC_12 13 +#define _CPPMAGIC_INC_13 14 +#define _CPPMAGIC_INC_14 15 +#define _CPPMAGIC_INC_15 16 +#define _CPPMAGIC_INC_16 17 +#define _CPPMAGIC_INC_17 18 +#define _CPPMAGIC_INC_18 19 +#define _CPPMAGIC_INC_19 20 +#define _CPPMAGIC_INC_20 21 +#define _CPPMAGIC_INC_21 22 +#define _CPPMAGIC_INC_22 23 +#define _CPPMAGIC_INC_23 24 +#define _CPPMAGIC_INC_24 25 +#define _CPPMAGIC_INC_25 26 +#define _CPPMAGIC_INC_26 27 +#define _CPPMAGIC_INC_27 28 +#define _CPPMAGIC_INC_28 29 +#define _CPPMAGIC_INC_29 30 +#define _CPPMAGIC_INC_30 31 +#define _CPPMAGIC_INC_31 32 +#define _CPPMAGIC_INC_32 32 + #endif /* CCAN_CPPMAGIC_H */ From patchwork Wed Jun 20 05:34:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Popple X-Patchwork-Id: 931958 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 419YS80tsJz9s4w for ; Wed, 20 Jun 2018 15:34:48 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 419YS76qrczF0wb for ; Wed, 20 Jun 2018 15:34:47 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Received: from ozlabs.org (ozlabs.org [IPv6:2401:3900:2:1::2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 419YRb0JdHzF0wq for ; Wed, 20 Jun 2018 15:34:19 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from authenticated.ozlabs.org (localhost [127.0.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPSA id 419YRZ3dwRz9s7c; Wed, 20 Jun 2018 15:34:18 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au From: Alistair Popple To: pdbg@lists.ozlabs.org Date: Wed, 20 Jun 2018 15:34:05 +1000 Message-Id: <20180620053409.14538-5-alistair@popple.id.au> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180620053409.14538-1-alistair@popple.id.au> References: <20180620053409.14538-1-alistair@popple.id.au> Subject: [Pdbg] [PATCH 4/8] ccan/cppmaigc: Add CPPMAGIC_MAP_CNT(...) macro X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" It can be useful to have a count to keep track of which argument number in the list is being expanded. Signed-off-by: Alistair Popple --- ccan/cppmagic/cppmagic.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ccan/cppmagic/cppmagic.h b/ccan/cppmagic/cppmagic.h index ffd5848..4cfb892 100644 --- a/ccan/cppmagic/cppmagic.h +++ b/ccan/cppmagic/cppmagic.h @@ -177,6 +177,25 @@ () /** + * CPPMAGIC_MAP_CNT - iterate antoher macro across arguments adding a count + * @m: name of a two argument macro + * + * CPPMAGIC_MAP_CNT(@m, @a1, @a2, ..., @an) + * expands to the expansion of + * @m(0, @a1) , @m(1, @a2) , ... , @m(n - 1, @an) + */ +#define _CPPMAGIC_MAP_CNT_() _CPPMAGIC_MAP_CNT +#define _CPPMAGIC_MAP_CNT(m_, c_, a_, ...) \ + m_(c_, a_) \ + CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \ + (, CPPMAGIC_DEFER2(_CPPMAGIC_MAP_CNT_)()(m_, CPPMAGIC_INC(c_), __VA_ARGS__)) \ + () +#define CPPMAGIC_MAP_CNT(m_, ...) \ + CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \ + (CPPMAGIC_EVAL(_CPPMAGIC_MAP_CNT(m_, 0, __VA_ARGS__))) \ + () + +/** * CPPMAGIC_JOIN - separate arguments with given delimiter * @d: delimiter * From patchwork Wed Jun 20 05:34:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Popple X-Patchwork-Id: 931959 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 419YSB1SB5z9s7X for ; Wed, 20 Jun 2018 15:34:50 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 419YS95hNjzF0x7 for ; Wed, 20 Jun 2018 15:34:49 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Received: from ozlabs.org (bilbo.ozlabs.org [203.11.71.1]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 419YRb3x6dzF0wk for ; Wed, 20 Jun 2018 15:34:19 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from authenticated.ozlabs.org (localhost [127.0.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPSA id 419YRb07Ydz9s8J; Wed, 20 Jun 2018 15:34:19 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au From: Alistair Popple To: pdbg@lists.ozlabs.org Date: Wed, 20 Jun 2018 15:34:06 +1000 Message-Id: <20180620053409.14538-6-alistair@popple.id.au> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180620053409.14538-1-alistair@popple.id.au> References: <20180620053409.14538-1-alistair@popple.id.au> Subject: [Pdbg] [PATCH 5/8] pdbg: Add command/flag parsing definitions X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" Add code to support command argument and flag parsing. A future patch will update existing code to use these parsers. The idea behind this code is to allow easily calling C functions from the command line without requiring shim/boilerplate functions to marshal arguments and flags which can be repetitive and error prone. In general a command consists of positional arguments and non-positional flags which optionally take arguments as shown below: cmd_name ... --flag1= --flag2 ... --flagM It supports default values for the last N postional arguments which allows trailing arguments to be made optional. The above definition allows a function with the following prototype to be called directly without any manual shim code: cmd_name(arg1, arg2, ... argN, flags) Where `flags` is a struct defined elsewhere containing fields which will match with the flag specification. Signed-off-by: Alistair Popple --- Makefile.am | 13 ++++- src/optcmd.c | 110 +++++++++++++++++++++++++++++++++++ src/optcmd.h | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 src/optcmd.c create mode 100644 src/optcmd.h diff --git a/Makefile.am b/Makefile.am index f0274b1..b860e14 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,8 +27,17 @@ DT_headers = $(DT:.dts=.dt.h) BUILT_SOURCES = $(DT) $(DT_headers) pdbg_SOURCES = \ - src/main.c src/cfam.c src/scom.c src/reg.c src/mem.c src/thread.c \ - src/ring.c src/htm.c src/progress.c src/options_@ARCH@.c + src/main.c \ + src/cfam.c \ + src/scom.c \ + src/reg.c \ + src/mem.c \ + src/thread.c \ + src/ring.c \ + src/htm.c \ + src/progress.c \ + src/optcmd.c \ + src/options_@ARCH@.c pdbg_LDADD = $(DT_objects) libpdbg.la libfdt.la \ -L.libs -lrt diff --git a/src/optcmd.c b/src/optcmd.c new file mode 100644 index 0000000..f6d2690 --- /dev/null +++ b/src/optcmd.c @@ -0,0 +1,110 @@ +/* Copyright 2016 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include + +#include "optcmd.h" + +/* Parse a flag of the form "--long-flag=" or "-F " */ +static int optcmd_parse_flag(const char *argv, struct optcmd_flag *flags, + int flag_count, void **flag_results) +{ + int i; + char *flag, *arg; + + flag = strdup(argv); + arg = strchr(flag, '='); + if (arg) { + *arg = '\0'; + arg++; + } + + for (i = 0; i < flag_count; i++) { + if (!strcmp(flag, flags[i].name)) { + flag_results[i] = flags[i].arg(arg); + if (!flag_results[i]) { + printf("Unable to parse argument for %s\n", flag); + return 1; + } + + return 0; + } + } + + printf("Invalid flag %s specified\n", flag); + return 1; +} + +/* Parse command arguments and flags */ +optcmd_cmd_t *optcmd_parse(struct optcmd_cmd *cmd, const char *argv[], int argc, + void **arg_results[], void **flag_results[]) +{ + int i, arg_count = 0, total_arg_count, total_flag_count; + struct optcmd_arg *args = cmd->args; + struct optcmd_flag *flags = cmd->flags; + void **tmp_arg_results, **tmp_flag_results; + + /* Allocate space for parser results */ + for (total_arg_count = 0; args[total_arg_count].parser && total_arg_count < OPTCMD_MAX_ARGS; total_arg_count++) {} + for (total_flag_count = 0; flags[total_flag_count].arg && total_flag_count < OPTCMD_MAX_FLAGS; total_flag_count++) {} + tmp_arg_results = malloc(total_arg_count*sizeof(void *)); + assert(tmp_arg_results); + tmp_flag_results = calloc(1, total_flag_count*sizeof(void *)); + assert(tmp_flag_results); + + for (i = 0; i < argc; i++, argv++) { + if (!strncmp(*argv, "--", 2)) { + if (optcmd_parse_flag(*argv, flags, total_flag_count, tmp_flag_results)) + /* Unable to parse flag */ + return NULL; + } else { + if (arg_count >= total_arg_count) { + printf("Too many arguments passed to %s\n", cmd->cmd); + return NULL; + } + + tmp_arg_results[arg_count] = args[arg_count].parser(*argv); + if (!tmp_arg_results[arg_count]) { + printf("Unable to parse argument %s\n", *argv); + return NULL; + } + arg_count++; + } + } + + for (arg_count = arg_count; arg_count < total_arg_count; arg_count++) { + /* Process default positional arguments */ + struct optcmd_arg *arg = &args[arg_count]; + + if (!arg->def) { + printf("Not enough arguments passed to %s\n", cmd->cmd); + return NULL; + } + + tmp_arg_results[arg_count] = arg->parser(arg->def); + if (!tmp_arg_results[arg_count]) { + printf("Programming error - unable to parse default argument %s\n", arg->def); + return NULL; + } + } + + *arg_results = tmp_arg_results; + *flag_results = tmp_flag_results; + + return cmd->cmdp; +} diff --git a/src/optcmd.h b/src/optcmd.h new file mode 100644 index 0000000..e5f688e --- /dev/null +++ b/src/optcmd.h @@ -0,0 +1,185 @@ +/* Copyright 2016 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __OPTCMD_H +#define __OPTCMD_H + +#include "ccan/check_type/check_type.h" +#include "ccan/build_assert/build_assert.h" +#include "ccan/cppmagic/cppmagic.h" +#include "config.h" + +#include "parsers.h" + +#ifndef OPTCMD_MAX_ARGS +#define OPTCMD_MAX_ARGS 10 +#endif + +#ifndef OPTCMD_MAX_FLAGS +#define OPTCMD_MAX_FLAGS 10 +#endif + +/* + * The idea of this module is to assist with easily calling C functions from the + * command line without requiring shim/boilerplate functions to marshal + * arguments and flags correctly which can be repetitive and error prone. + * + * In general a command consists of positional arguments and non-positional + * flags which optionally take arguments as shown below: + * + * `cmd_name ... --flag1= --flag2 ... --flagM` + * + * It supports default values for the last N postional arguments which allows + * trailing arguments to be made optional. The above definition allows a + * function with the following prototype to be called directly: + * + * `cmd_name(arg1, arg2, ... argN, flags)` + * + * Where `flags` is a struct defined elsewhere containing fields which will + * match with the flags specified above. + * + * TODO: + * - Add support for short flags (ie. `-f `) + * + * - Add a function to free memory. The parsers allocate memory but it's never + * freed. Not a big issue though as the program tends to execute one command + * and exit. + */ + +typedef void * (optcmd_parser_t)(const char *argv); +typedef int (optcmd_cmd_t)(void *[], void *[]); + +/* + * The below data structures are used internally to specify commands along with + * any arguments and flags. They could be filled out without any of the macro + * magic further down, however internally the parser results are all cast to + * (void *) which could result in weird errors if a function expecting a + * argument of type char is called with an int. + * + * Using the macros should guard against these types of errors by ensuring type + * mismatch errors will result in compiler warnings or errors (although sadly + * these tend to be rather noisy). + */ +struct optcmd_flag { + const char *name; + optcmd_parser_t *arg; +}; + +struct optcmd_arg { + optcmd_parser_t *parser; + const char *def; +}; + +struct optcmd_cmd { + const char *cmd; + optcmd_cmd_t *cmdp; + struct optcmd_arg args[OPTCMD_MAX_ARGS]; + struct optcmd_flag flags[OPTCMD_MAX_FLAGS]; +}; + +/* Casts the given parser to a generic parser returning void * and taking a + * char * argument. */ +#define OPTCMD_PARSER_CAST(parser_) ((optcmd_parser_t *) parser_) + +/* Returns the return type definition of the given parser */ +#define OPTCMD_TYPEOF_PARSER(parser_, ...) typeof(*parser_("")) + +/* Cast a postional argument to the right type */ +#define OPTCMD_CAST_ARG(cnt_, parser_) *(OPTCMD_TYPEOF_PARSER parser_ *) args[cnt_] + +/* Returns a positional argument struct */ +#define _OPTCMD_ARG(parser_, default_) { .parser = OPTCMD_PARSER_CAST(parser_), .def = default_ } +#define OPTCMD_ARG(pos_) _OPTCMD_ARG pos_ + +/* Returns the type definition for a postional argument */ +#define _OPTCMD_ARG_DEF(parser_, ...) OPTCMD_TYPEOF_PARSER(parser_) +#define OPTCMD_ARG_DEF(pos_) _OPTCMD_ARG_DEF pos_ + +/* Associate a specific flag name with a parser */ +#define _OPTCMD_FLAG(flag_, field_, parser_, ...) \ + { .name = flag_, .arg = OPTCMD_PARSER_CAST(parser_) } +#define OPTCMD_FLAG(flag_) _OPTCMD_FLAG flag_ + +/* Cast parser output to a specific flag field */ +#define _OPTCMD_CAST_FLAGS(flag_, field_, parser_, default_) \ + BUILD_ASSERT(!check_types_match(flag.field_, OPTCMD_TYPEOF_PARSER(parser_))); \ + flag.field_ = *flags ? *(OPTCMD_TYPEOF_PARSER(parser_) *) *flags : default_; \ + flags++; +#define OPTCMD_CAST_FLAGS(flags_) _OPTCMD_CAST_FLAGS flags_ + +/* + * Defines a new command with arguments and flags. + * @cmd_name - name of command used on the command line + * @cmd_func - pointer to the function to call for this command + * @pos - list of positional arguments in the form ((parser, , "help text"), ...) + * @flag - name of flag struct to pass @cmd_func as the last parameter + * @flags - list of flags in the form (("--flag-name", , parser, , "help text"), ...) + */ +#define OPTCMD_DEFINE_CMD_WITH_FLAGS(cmd_name_, cmd_func_, pos_, flag_, flags_) \ + int cmd_func_(CPPMAGIC_MAP(OPTCMD_ARG_DEF, CPPMAGIC_EVAL pos_), struct flag_); \ + int __##cmd_func_(void *args[], void *flags[]) \ + { \ + struct flag_ flag; \ + CPPMAGIC_JOIN(, CPPMAGIC_MAP(OPTCMD_CAST_FLAGS, CPPMAGIC_EVAL flags_)) \ + return cmd_func_(CPPMAGIC_MAP_CNT(OPTCMD_CAST_ARG, CPPMAGIC_EVAL pos_), flag); \ + } \ + \ + struct optcmd_cmd optcmd_##cmd_name_ = { \ + .cmd = #cmd_name_, \ + .cmdp = __##cmd_func_, \ + .args = { CPPMAGIC_MAP(OPTCMD_ARG, CPPMAGIC_EVAL pos_), {NULL} }, \ + .flags = { CPPMAGIC_MAP(OPTCMD_FLAG, CPPMAGIC_EVAL flags_), {NULL} }, \ + } + +/* + * Defines a new command with arguments. + * @cmd_name - name of command used on the command line + * @cmd_func - pointer to the function to call for this command + * @pos - list of positional arguments in the form ((parser, , "help text"), ...) + */ +#define OPTCMD_DEFINE_CMD_WITH_ARGS(cmd_name_, cmd_func_, pos_) \ + int cmd_func_(CPPMAGIC_MAP(OPTCMD_ARG_DEF, CPPMAGIC_EVAL pos_)); \ + int __##cmd_func_(void *args[], void *flags[]) \ + { \ + return cmd_func_(CPPMAGIC_MAP_CNT(OPTCMD_CAST_ARG, CPPMAGIC_EVAL pos_)); \ + } \ + \ + struct optcmd_cmd optcmd_##cmd_name_ = { \ + .cmd = #cmd_name_, \ + .cmdp = __##cmd_func_, \ + .args = { CPPMAGIC_MAP(OPTCMD_ARG, CPPMAGIC_EVAL pos_), {NULL} }, \ + } + +/* + * Defines a new command taking no arguments or flags. + * @cmd_name - name of command used on the command line + * @cmd_func - pointer to the function to call for this command + */ +#define OPTCMD_DEFINE_CMD(cmd_name_, cmd_func_) \ + int cmd_func_(void); \ + int __##cmd_func_(void *args[], void *flags[]) \ + { \ + return cmd_func_(); \ + } \ + \ + struct optcmd_cmd optcmd_##cmd_name_ = { \ + .cmd = #cmd_name_, \ + .cmdp = __##cmd_func_, \ + } + +optcmd_cmd_t *optcmd_parse(struct optcmd_cmd *cmd, const char *argv[], int argc, + void **args[], void **flags[]); + +#endif From patchwork Wed Jun 20 05:34:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Popple X-Patchwork-Id: 931960 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 419YSD11hDz9s7X for ; Wed, 20 Jun 2018 15:34:52 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 419YSC6pJyzF10W for ; Wed, 20 Jun 2018 15:34:51 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Received: from ozlabs.org (bilbo.ozlabs.org [203.11.71.1]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 419YRb5YGhzF0wf for ; Wed, 20 Jun 2018 15:34:19 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from authenticated.ozlabs.org (localhost [127.0.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPSA id 419YRb2wy6z9s9L; Wed, 20 Jun 2018 15:34:19 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au From: Alistair Popple To: pdbg@lists.ozlabs.org Date: Wed, 20 Jun 2018 15:34:07 +1000 Message-Id: <20180620053409.14538-7-alistair@popple.id.au> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180620053409.14538-1-alistair@popple.id.au> References: <20180620053409.14538-1-alistair@popple.id.au> Subject: [Pdbg] [PATCH 6/8] pdbg: Define common command/flag argument parsers X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" Parsers need to take a string argument and convert it into a specific type, returning the value as a pointer to memory allocated by the parser (or NULL in the case of an error). This just defines a couple of common parsers useful for various commands. It also defines a couple of convenience macros for easier usage of these parsers. Signed-off-by: Alistair Popple --- src/parsers.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/parsers.h | 21 +++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 src/parsers.c create mode 100644 src/parsers.h diff --git a/src/parsers.c b/src/parsers.c new file mode 100644 index 0000000..0399933 --- /dev/null +++ b/src/parsers.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +uint64_t *parse_number64(const char *argv) +{ + uint64_t *n = malloc(sizeof(*n)); + char *endptr; + + if (!argv) + return NULL; + + errno = 0; + *n = strtoull(argv, &endptr, 0); + if (errno || *endptr != '\0') + return NULL; + + return n; +} + +uint32_t *parse_number32(const char *argv) +{ + unsigned long long tmp; + uint32_t *n = malloc(sizeof(*n)); + char *endptr; + + if (!argv) + return NULL; + + errno = 0; + tmp = strtoul(argv, &endptr, 0); + if (errno || *endptr != '\0' || tmp > (uint32_t) -1UL) + return NULL; + + *n = tmp; + return n; +} + +/* Parse a GPR number, returning an error if it's greater than 32 */ +int *parse_gpr(const char *argv) +{ + int *gpr = malloc(sizeof(*gpr)); + char *endptr; + + if (!argv) + return NULL; + + errno = 0; + *gpr = strtoul(argv, &endptr, 0); + if (errno || *endptr != '\0' || *gpr > 32) + return NULL; + + return gpr; +} + +/* Parse an SPR. Currently only supports SPR by numbers but could be extended to + * support names (eg. lr) */ +int *parse_spr(const char *argv) +{ + int *spr = malloc(sizeof(*spr)); + char *endptr; + + if (!argv) + return NULL; + + errno = 0; + *spr = strtoul(argv, &endptr, 0); + if (errno || *endptr != '\0' || *spr > 0x3ff) + return NULL; + + return spr; +} + + +/* A special parser that always returns true. Allows for boolean flags which + * don't take arguments. Sets the associated field to true if specified, + * otherwise sets it to the default value (usually false). */ +bool *parse_flag_noarg(const char *argv) +{ + bool *result = malloc(sizeof(*result)); + + *result = true; + return result; +} diff --git a/src/parsers.h b/src/parsers.h new file mode 100644 index 0000000..b5f23cf --- /dev/null +++ b/src/parsers.h @@ -0,0 +1,21 @@ +#ifndef __PARSERS_H +#define __PARSERS_H + +#include +#include + +#define ADDRESS (parse_number64, NULL) +#define ADDRESS32 (parse_number32, NULL) +#define DATA (parse_number64, NULL) +#define DATA32 (parse_number32, NULL) +#define DEFAULT_DATA(default) (parse_number64, default) +#define GPR (parse_gpr, NULL) +#define SPR (parse_spr, NULL) + +uint64_t *parse_number64(const char *argv); +uint32_t *parse_number32(const char *argv); +int *parse_gpr(const char *argv); +int *parse_spr(const char *argv); +bool *parse_flag_noarg(const char *argv); + +#endif From patchwork Wed Jun 20 05:34:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Popple X-Patchwork-Id: 931961 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 419YSG1L3Qz9s4n for ; Wed, 20 Jun 2018 15:34:54 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 419YSF6lPmzF0x7 for ; Wed, 20 Jun 2018 15:34:53 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Received: from ozlabs.org (ozlabs.org [IPv6:2401:3900:2:1::2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 419YRc1wvBzF0wq for ; Wed, 20 Jun 2018 15:34:20 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from authenticated.ozlabs.org (localhost [127.0.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPSA id 419YRb6vxBz9s9T; Wed, 20 Jun 2018 15:34:19 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au From: Alistair Popple To: pdbg@lists.ozlabs.org Date: Wed, 20 Jun 2018 15:34:08 +1000 Message-Id: <20180620053409.14538-8-alistair@popple.id.au> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180620053409.14538-1-alistair@popple.id.au> References: <20180620053409.14538-1-alistair@popple.id.au> Subject: [Pdbg] [PATCH 7/8] optcmd: Add tests X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" We don't really have infrastructure in place to easily add/build/run tests, but that shouldn't stop them being written. This adds some basic tests of the argument parsing logic. Signed-off-by: Alistair Popple --- Makefile.am | 5 +- src/tests/optcmd_test.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 src/tests/optcmd_test.c diff --git a/Makefile.am b/Makefile.am index b860e14..23f2080 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,7 +3,7 @@ AM_MAKEFLAGS = --no-print-directory GIT_SHA1 ?= `git --work-tree=$(top_srcdir) --git-dir=$(top_srcdir)/.git describe --always --long --dirty || echo unknown` -bin_PROGRAMS = pdbg +bin_PROGRAMS = pdbg optcmd_test ACLOCAL_AMFLAGS = -Im4 AM_CFLAGS = -I$(top_srcdir)/ccan/array_size -Wall -Werror -O2 @@ -26,6 +26,9 @@ DT_headers = $(DT:.dts=.dt.h) BUILT_SOURCES = $(DT) $(DT_headers) +optcmd_test_SOURCES = src/optcmd.c src/parsers.c src/tests/optcmd_test.c +optcmd_test_CFLAGS = -Wall -g + pdbg_SOURCES = \ src/main.c \ src/cfam.c \ diff --git a/src/tests/optcmd_test.c b/src/tests/optcmd_test.c new file mode 100644 index 0000000..bfa0667 --- /dev/null +++ b/src/tests/optcmd_test.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include + +#include "../optcmd.h" +#include "../parsers.h" + +/* The OPTCMD_TEST_BREAK_BUILD* defines can be used to test that we catch type + * mistmatch errors between function/flag definitions and parsers */ +#ifdef OPTCMD_TEST_BREAK_BUILD1 +struct flags { + bool test_bool; + int test_num; +}; +#else +struct flags { + bool test_bool; + uint64_t test_num; +}; +#endif + +/* Format: (, , , ) */ +#define FLAG_TEST_BOOL ("--test-bool", test_bool, parse_flag_noarg, false) +#define FLAG_TEST_NUM ("--test-num", test_num, parse_number64, 10) + +/* Format: (, ) + * + * may be NULL if argument must be supplied. + */ +#define ARG_NUM (parse_number64, NULL) +#define ARG_NUM_OPT (parse_number64, "2") + +static uint64_t num, opt, flag; +static bool bool_flag; + +static int test(void) +{ + bool_flag = true; + + return 0; +} +OPTCMD_DEFINE_CMD(test, test); + +#ifdef OPTCMD_TEST_BREAK_BUILD2 +static int test_args(int num_arg, int opt_arg) +{ + return 0; +} +#else +static int test_args(uint64_t num_arg, uint64_t opt_arg) +{ + num = num_arg; + opt = opt_arg; + + return 0; +} +#endif +OPTCMD_DEFINE_CMD_WITH_ARGS(test_args, test_args, (ARG_NUM, ARG_NUM_OPT)); + +static int test_flags(uint64_t num_arg, uint64_t opt_arg, struct flags flags) +{ + num = num_arg; + opt = opt_arg; + flag = flags.test_num; + bool_flag = flags.test_bool; + + return 0; +} +OPTCMD_DEFINE_CMD_WITH_FLAGS(test_flags, test_flags, (ARG_NUM, ARG_NUM_OPT), + flags, (FLAG_TEST_BOOL, FLAG_TEST_NUM)); + +int parse_argv(const char *argv[], int argc) +{ + int i, rc; + void **args, **flags; + struct optcmd_cmd *cmds[] = { &optcmd_test, &optcmd_test_args, &optcmd_test_flags }; + optcmd_cmd_t *cmd; + + for (i = 0; i < ARRAY_SIZE(cmds); i++) { + if (!strcmp(argv[0], cmds[i]->cmd)) { + /* Found our command */ + cmd = optcmd_parse(cmds[i], &argv[1], argc - 1, &args, &flags); + if (cmd) { + rc = cmd(args, flags); + return rc; + } + } + } + + return -1; +} + +int main(void) +{ + /* Tests */ + const char *test1_argv[] = { "test" }; + bool_flag = false; + assert(!parse_argv(test1_argv, ARRAY_SIZE(test1_argv))); + assert(bool_flag); + + const char *test2_argv[] = { "test_args", "1" }; + assert(!parse_argv(test2_argv, ARRAY_SIZE(test2_argv))); + assert(num == 1); + assert(opt == 2); + + const char *test3_argv[] = { "test_args", "2", "3" }; + assert(!parse_argv(test3_argv, ARRAY_SIZE(test3_argv))); + assert(num == 2); + assert(opt == 3); + + const char *test4_argv[] = { "test_flags", "4", "5" }; + assert(!parse_argv(test4_argv, ARRAY_SIZE(test4_argv))); + assert(num == 4); + assert(opt == 5); + assert(flag == 10); + + bool_flag = false; + + const char *test5_argv[] = { "test_flags", "5", "6" }; + assert(!parse_argv(test5_argv, ARRAY_SIZE(test5_argv))); + assert(num == 5); + assert(opt == 6); + assert(flag == 10); + assert(!bool_flag); + + const char *test6_argv[] = { "test_flags", "7", "8", "--test-num=9" }; + assert(!parse_argv(test6_argv, ARRAY_SIZE(test6_argv))); + assert(num == 7); + assert(opt == 8); + assert(flag == 9); + assert(!bool_flag); + + const char *test7_argv[] = { "test_flags", "8", "9", "--test-bool" }; + assert(!parse_argv(test7_argv, ARRAY_SIZE(test7_argv))); + assert(num == 8); + assert(opt == 9); + assert(flag == 10); + assert(bool_flag); + + bool_flag = false; + + const char *test8_argv[] = { "test_flags", "9", "10", "--test-bool", "--test-num=11" }; + assert(!parse_argv(test8_argv, ARRAY_SIZE(test8_argv))); + assert(num == 9); + assert(opt == 10); + assert(flag == 11); + assert(bool_flag); + + /* This should fail, too many arguments */ + const char *test9_argv[] = { "test_flags", "9", "10", "11", "--test-bool", "--test-num=11" }; + assert(parse_argv(test9_argv, ARRAY_SIZE(test9_argv))); + + /* So should this, unknown flag */ + const char *test10_argv[] = { "test_flags", "9", "10", "--test-blah", "--test-num=11" }; + assert(parse_argv(test10_argv, ARRAY_SIZE(test10_argv))); + + return 0; +} From patchwork Wed Jun 20 05:34:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Popple X-Patchwork-Id: 931962 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 419YSJ2JMjz9s4n for ; Wed, 20 Jun 2018 15:34:56 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 419YSJ0VzYzF10W for ; Wed, 20 Jun 2018 15:34:56 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Received: from ozlabs.org (bilbo.ozlabs.org [203.11.71.1]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 419YRc3wP4zF0x7 for ; Wed, 20 Jun 2018 15:34:20 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from authenticated.ozlabs.org (localhost [127.0.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPSA id 419YRc1qrSz9s4n; Wed, 20 Jun 2018 15:34:20 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au From: Alistair Popple To: pdbg@lists.ozlabs.org Date: Wed, 20 Jun 2018 15:34:09 +1000 Message-Id: <20180620053409.14538-9-alistair@popple.id.au> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180620053409.14538-1-alistair@popple.id.au> References: <20180620053409.14538-1-alistair@popple.id.au> Subject: [Pdbg] [PATCH 8/8] pdbg: Use new command parsing X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" This switches all commands except the htm command to use the new command/option parsing code. For the moment we leave the usage help and generic targeting flag processing alone, but future changes should allow this to also use the common parsing code. Signed-off-by: Alistair Popple Signed-off-by: Alistair Popple <alistair@popple.id.au>
--- Makefile.am | 1 + src/cfam.c | 55 ++++++-------------- src/cfam.h | 18 ------- src/main.c | 125 ++++++++++++++++++++++++++++----------------- src/mem.c | 124 ++++++++------------------------------------ src/mem.h | 20 -------- src/reg.c | 164 +++++++++++++++-------------------------------------------- src/reg.h | 20 -------- src/ring.c | 32 ++---------- src/ring.h | 17 ------- src/scom.c | 54 +++++--------------- src/scom.h | 18 ------- src/thread.c | 87 ++++++++++++++++++++++--------- src/thread.h | 23 --------- 14 files changed, 237 insertions(+), 521 deletions(-) delete mode 100644 src/cfam.h delete mode 100644 src/mem.h delete mode 100644 src/reg.h delete mode 100644 src/ring.h delete mode 100644 src/scom.h delete mode 100644 src/thread.h diff --git a/Makefile.am b/Makefile.am index 23f2080..4e0dce2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,6 +39,7 @@ pdbg_SOURCES = \ src/ring.c \ src/htm.c \ src/progress.c \ + src/parsers.c \ src/optcmd.c \ src/options_@ARCH@.c diff --git a/src/cfam.c b/src/cfam.c index 269123e..6dab388 100644 --- a/src/cfam.c +++ b/src/cfam.c @@ -20,8 +20,9 @@ #include #include "main.h" +#include "optcmd.h" -static int getcfam(struct pdbg_target *target, uint32_t index, uint64_t *addr, uint64_t *unused) +static int _getcfam(struct pdbg_target *target, uint32_t index, uint64_t *addr, uint64_t *unused) { uint32_t value; @@ -33,7 +34,15 @@ static int getcfam(struct pdbg_target *target, uint32_t index, uint64_t *addr, u return 1; } -static int putcfam(struct pdbg_target *target, uint32_t index, uint64_t *addr, uint64_t *data) +static int getcfam(uint32_t addr) +{ + uint64_t addr64 = addr; + + return for_each_target("fsi", _getcfam, &addr64, NULL); +} +OPTCMD_DEFINE_CMD_WITH_ARGS(getcfam, getcfam, (ADDRESS32)); + +static int _putcfam(struct pdbg_target *target, uint32_t index, uint64_t *addr, uint64_t *data) { if (fsi_write(target, *addr, *data)) return 0; @@ -41,44 +50,10 @@ static int putcfam(struct pdbg_target *target, uint32_t index, uint64_t *addr, u return 1; } -int handle_cfams(int optind, int argc, char *argv[]) +static int putcfam(uint32_t addr, uint32_t data) { - uint64_t addr; - char *endptr; - - if (optind + 1 >= argc) { - printf("%s: command '%s' requires an address\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - addr = strtoull(argv[optind + 1], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse address '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } + uint64_t addr64 = addr, data64 = data; - if (strcmp(argv[optind], "putcfam") == 0) { - uint64_t data; - - if (optind + 2 >= argc) { - printf("%s: command '%s' requires data\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - data = strtoull(argv[optind + 2], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse data '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } - - return for_each_target("fsi", putcfam, &addr, &data); - } - - return for_each_target("fsi", getcfam, &addr, NULL); + return for_each_target("fsi", _putcfam, &addr64, &data64); } - - +OPTCMD_DEFINE_CMD_WITH_ARGS(putcfam, putcfam, (ADDRESS32, DATA32)); diff --git a/src/cfam.h b/src/cfam.h deleted file mode 100644 index 997ed3d..0000000 --- a/src/cfam.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2017 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -int handle_cfams(int optind, int argc, char *argv[]); diff --git a/src/main.c b/src/main.c index cf9a3b2..1cfaca7 100644 --- a/src/main.c +++ b/src/main.c @@ -34,14 +34,9 @@ #include #include "main.h" -#include "cfam.h" -#include "scom.h" -#include "reg.h" -#include "ring.h" -#include "mem.h" -#include "thread.h" #include "htm.h" #include "options.h" +#include "optcmd.h" #define PR_ERROR(x, args...) \ pdbg_log(PDBG_ERROR, x, ##args) @@ -77,44 +72,64 @@ static int **processorsel[MAX_PROCESSORS]; static int *chipsel[MAX_PROCESSORS][MAX_CHIPS]; static int threadsel[MAX_PROCESSORS][MAX_CHIPS][MAX_THREADS]; -static int handle_probe(int optind, int argc, char *argv[]); -static int handle_release(int optind, int argc, char *argv[]); +static int probe(void); +static int release(void); + +/* TODO: We are repeating ourselves here. A little bit more macro magic could + * easily fix this but I was hesitant to introduce too much magic all at + * once. */ +extern struct optcmd_cmd + optcmd_getscom, optcmd_putscom, optcmd_getcfam, optcmd_putcfam, + optcmd_getgpr, optcmd_putgpr, optcmd_getspr, optcmd_putspr, + optcmd_getnia, optcmd_putnia, optcmd_getmsr, optcmd_putmsr, + optcmd_getring, optcmd_start, optcmd_stop, optcmd_step, + optcmd_threadstatus, optcmd_sreset, optcmd_regs, optcmd_probe, + optcmd_getmem, optcmd_putmem; + +static struct optcmd_cmd *cmds[] = { + &optcmd_getscom, &optcmd_putscom, &optcmd_getcfam, &optcmd_putcfam, + &optcmd_getgpr, &optcmd_putgpr, &optcmd_getspr, &optcmd_putspr, + &optcmd_getnia, &optcmd_putnia, &optcmd_getmsr, &optcmd_putmsr, + &optcmd_getring, &optcmd_start, &optcmd_stop, &optcmd_step, + &optcmd_threadstatus, &optcmd_sreset, &optcmd_regs, &optcmd_probe, + &optcmd_getmem, &optcmd_putmem, +}; +/* Purely for printing usage text. We could integrate printing argument and flag + * help into optcmd if desired. */ struct action { const char *name; const char *args; const char *desc; - int (*fn)(int, int, char **); }; static struct action actions[] = { - { "getgpr", "", "Read General Purpose Register (GPR)", &handle_gpr }, - { "putgpr", " ", "Write General Purpose Register (GPR)", &handle_gpr }, - { "getnia", "", "Get Next Instruction Address (NIA)", &handle_nia }, - { "putnia", "", "Write Next Instrution Address (NIA)", &handle_nia }, - { "getspr", "", "Get Special Purpose Register (SPR)", &handle_spr }, - { "putspr", " ", "Write Special Purpose Register (SPR)", &handle_spr }, - { "getmsr", "", "Get Machine State Register (MSR)", &handle_msr }, - { "putmsr", "", "Write Machine State Register (MSR)", &handle_msr }, - { "getring", " ", "Read a ring. Length must be correct", &handle_getring }, - { "start", "", "Start thread", &thread_start }, - { "step", "", "Set a thread instructions", &thread_step }, - { "stop", "", "Stop thread", &thread_stop }, - { "htm", "core|nest start|stop|status|reset|dump|trace|analyse", "Hardware Trace Macro", &run_htm }, - { "release", "", "Should be called after pdbg work is finished, to release special wakeups and other resources.", &handle_release}, - { "probe", "", "", &handle_probe }, - { "getcfam", "
", "Read system cfam", &handle_cfams }, - { "putcfam", "
[]", "Write system cfam", &handle_cfams }, - { "getscom", "
", "Read system scom", &handle_scoms }, - { "putscom", "
[]", "Write system scom", &handle_scoms }, - { "getmem", "
", "Read system memory", &handle_mem }, - { "putmem", "
", "Write to system memory", &handle_mem }, - { "threadstatus", "", "Print the status of a thread", &thread_status_print }, - { "sreset", "", "Reset", &thread_sreset }, - { "regs", "", "State", &thread_state }, + { "getgpr", "", "Read General Purpose Register (GPR)" }, + { "putgpr", " ", "Write General Purpose Register (GPR)" }, + { "getnia", "", "Get Next Instruction Address (NIA)" }, + { "putnia", "", "Write Next Instrution Address (NIA)" }, + { "getspr", "", "Get Special Purpose Register (SPR)" }, + { "putspr", " ", "Write Special Purpose Register (SPR)" }, + { "getmsr", "", "Get Machine State Register (MSR)" }, + { "putmsr", "", "Write Machine State Register (MSR)" }, + { "getring", " ", "Read a ring. Length must be correct" }, + { "start", "", "Start thread" }, + { "step", "", "Set a thread instructions" }, + { "stop", "", "Stop thread" }, + { "htm", "core|nest start|stop|status|reset|dump|trace|analyse", "Hardware Trace Macro" }, + { "release", "", "Should be called after pdbg work is finished" }, + { "probe", "", "" }, + { "getcfam", "
", "Read system cfam" }, + { "putcfam", "
[]", "Write system cfam" }, + { "getscom", "
", "Read system scom" }, + { "putscom", "
[]", "Write system scom" }, + { "getmem", "
", "Read system memory" }, + { "putmem", "
", "Write to system memory" }, + { "threadstatus", "", "Print the status of a thread" }, + { "sreset", "", "Reset" }, + { "regs", "", "State" }, }; - static void print_usage(char *pname) { int i; @@ -600,7 +615,7 @@ static void release_target(struct pdbg_target *target) pdbg_target_release(target); } -static void do_release(void) +static int release(void) { struct pdbg_target_class *target_class; @@ -610,7 +625,10 @@ static void do_release(void) pdbg_for_each_class_target(target_class->name, target) release_target(target); } + + return 0; } +OPTCMD_DEFINE_CMD(release, release); void print_target(struct pdbg_target *target, int level) { @@ -652,7 +670,7 @@ void print_target(struct pdbg_target *target, int level) } } -static int handle_probe(int optind, int argc, char *argv[]) +static int probe(void) { struct pdbg_target *target; @@ -664,25 +682,21 @@ static int handle_probe(int optind, int argc, char *argv[]) return 1; } +OPTCMD_DEFINE_CMD(probe, probe); /* * Release handler. */ static void atexit_release(void) { - do_release(); -} - -static int handle_release(int optind, int argc, char *argv[]) -{ - do_release(); - - return 1; + release(); } int main(int argc, char *argv[]) { int i, rc = 0; + void **args, **flags; + optcmd_cmd_t *cmd; backend = default_backend(); device_node = default_target(backend); @@ -714,13 +728,28 @@ int main(int argc, char *argv[]) atexit(atexit_release); - for (i = 0; i < ARRAY_SIZE(actions); i++) { - if (strcmp(argv[optind], actions[i].name) == 0) { - rc = actions[i].fn(optind, argc, argv); - goto found_action; + for (i = 0; i < ARRAY_SIZE(cmds); i++) { + if (!strcmp(argv[optind], cmds[i]->cmd)) { + /* Found our command */ + cmd = optcmd_parse(cmds[i], (const char **) &argv[optind + 1], + argc - (optind + 1), &args, &flags); + if (cmd) { + rc = cmd(args, flags); + goto found_action; + } else { + /* Error parsing arguments so exit return directly */ + return 1; + } } } + /* Process subcommands. Currently only 'htm'. + * TODO: Move htm command parsing to optcmd once htm clean-up is complete */ + if (!strcmp(argv[optind], "htm")) { + run_htm(optind, argc, argv); + goto found_action; + } + PR_ERROR("Unsupported command: %s\n", argv[optind]); return 1; diff --git a/src/mem.c b/src/mem.c index e0327d1..29fd21e 100644 --- a/src/mem.c +++ b/src/mem.c @@ -20,21 +20,34 @@ #include #include #include +#include #include #include "main.h" #include "progress.h" +#include "optcmd.h" +#include "parsers.h" #define PR_ERROR(x, args...) \ pdbg_log(PDBG_ERROR, x, ##args) #define PUTMEM_BUF_SIZE 1024 -static int getmem(uint64_t addr, uint64_t size, bool ci) + +struct mem_flags { + bool ci; +}; + +#define MEM_CI_FLAG ("--ci", ci, parse_flag_noarg, false) + +static int getmem(uint64_t addr, uint64_t size, struct mem_flags flags) { struct pdbg_target *target; uint8_t *buf; int rc = 0; + + printf("getmem ci %d\n", flags.ci); + buf = malloc(size); assert(buf); pdbg_for_each_class_target("adu", target) { @@ -43,7 +56,7 @@ static int getmem(uint64_t addr, uint64_t size, bool ci) pdbg_set_progress_tick(progress_tick); progress_init(); - if (!__adu_getmem(target, addr, buf, size, ci)) { + if (!__adu_getmem(target, addr, buf, size, flags.ci)) { if (write(STDOUT_FILENO, buf, size) < 0) PR_ERROR("Unable to write stdout.\n"); else @@ -58,7 +71,10 @@ static int getmem(uint64_t addr, uint64_t size, bool ci) return rc; } -static int putmem(uint64_t addr, bool ci) +OPTCMD_DEFINE_CMD_WITH_FLAGS(getmem, getmem, (ADDRESS, DATA), + mem_flags, (MEM_CI_FLAG)); + +static int putmem(uint64_t addr, struct mem_flags flags) { uint8_t *buf; int read_size, rc = 0; @@ -76,7 +92,7 @@ static int putmem(uint64_t addr, bool ci) progress_init(); do { read_size = read(STDIN_FILENO, buf, PUTMEM_BUF_SIZE); - if (__adu_putmem(adu_target, addr, buf, read_size, ci)) { + if (__adu_putmem(adu_target, addr, buf, read_size, flags.ci)) { rc = 0; printf("Unable to write memory.\n"); break; @@ -89,101 +105,5 @@ static int putmem(uint64_t addr, bool ci) free(buf); return rc; } - -static bool is_real_address(struct thread_regs *regs, uint64_t addr) -{ - return true; - if ((addr & 0xf000000000000000ULL) == 0xc000000000000000ULL) - return true; - return false; -} - -static int load8(struct pdbg_target *target, uint64_t addr, uint64_t *value) -{ - if (adu_getmem(target, addr, (uint8_t *)value, 8)) { - PR_ERROR("Unable to read memory address=%016" PRIx64 ".\n", addr); - return 0; - } - - return 1; -} - -int dump_stack(struct thread_regs *regs) -{ - struct pdbg_target *target; - uint64_t sp = regs->gprs[1]; - uint64_t pc; - - pdbg_for_each_class_target("adu", target) { - if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED) - continue; - break; - } - - printf("STACK:\n"); - if (!target) - PR_ERROR("Unable to read memory (no ADU found)\n"); - - if (sp && is_real_address(regs, sp)) { - if (!load8(target, sp, &sp)) - return 1; - while (sp && is_real_address(regs, sp)) { - if (!load8(target, sp + 16, &pc)) - return 1; - - printf(" 0x%016" PRIx64 " 0x%16" PRIx64 "\n", sp, pc); - - if (!load8(target, sp, &sp)) - return 1; - } - } - - return 0; -} - -int handle_mem(int optind, int argc, char *argv[]) -{ - uint64_t addr; - char *endptr; - bool ci = false; - - if (optind + 1 >= argc) { - printf("%s: command '%s' requires an address\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - - if (strcmp(argv[optind +1], "-ci") == 0) { - /* Set cache-inhibited flag */ - ci = true; - } - - addr = strtoull(argv[optind + 1 + ci], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse address '%s'\n", - argv[0], argv[optind], argv[optind + 1 + ci]); - return -1; - } - - if (strcmp(argv[optind], "getmem") == 0) { - uint64_t size; - - if (optind + 2 + ci >= argc) { - printf("%s: command '%s' requires data\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - size = strtoull(argv[optind + 2 + ci], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse data '%s'\n", - argv[0], argv[optind], argv[optind + 1 + ci]); - return -1; - } - - return getmem(addr, size, ci); - } - - return putmem(addr, ci); -} +OPTCMD_DEFINE_CMD_WITH_FLAGS(putmem, putmem, (ADDRESS), + mem_flags, (MEM_CI_FLAG)); diff --git a/src/mem.h b/src/mem.h deleted file mode 100644 index 42bdc04..0000000 --- a/src/mem.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2017 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include - -int dump_stack(struct thread_regs *regs); -int handle_mem(int optind, int argc, char *argv[]); diff --git a/src/reg.c b/src/reg.c index 21bec13..aa77a8a 100644 --- a/src/reg.c +++ b/src/reg.c @@ -22,6 +22,7 @@ #include #include "main.h" +#include "optcmd.h" #define REG_MEM -3 #define REG_MSR -2 @@ -91,143 +92,58 @@ static int getprocreg(struct pdbg_target *target, uint32_t index, uint64_t *reg, return !rc; } -int handle_gpr(int optind, int argc, char *argv[]) +static int getgpr(int gpr) { - char *endptr; - uint64_t gpr; - - if (optind + 1 >= argc) { - printf("%s: command '%s' requires a GPR\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - gpr = strtoull(argv[optind + 1], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse GPR '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } - - if (gpr > 31) { - printf("A GPR must be between zero and 31 inclusive\n"); - return -1; - } - - if (strcmp(argv[optind], "putgpr") == 0) { - uint64_t data; - - if (optind + 2 >= argc) { - printf("%s: command '%s' requires data\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - data = strtoull(argv[optind + 2], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse data '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } - - return for_each_target("thread", putprocreg, &gpr, &data); - } - - return for_each_target("thread", getprocreg, &gpr, NULL); + uint64_t reg = gpr; + return for_each_target("thread", getprocreg, ®, NULL); } +OPTCMD_DEFINE_CMD_WITH_ARGS(getgpr, getgpr, (GPR)); -int handle_nia(int optind, int argc, char *argv[]) +static int putgpr(int gpr, uint64_t data) { - uint64_t reg = REG_NIA; - char *endptr; - - if (strcmp(argv[optind], "putnia") == 0) { - uint64_t data; - - if (optind + 1 >= argc) { - printf("%s: command '%s' requires data\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - data = strtoull(argv[optind + 1], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse data '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } - - return for_each_target("thread", putprocreg, ®, &data); - } + uint64_t reg = gpr; + return for_each_target("thread", putprocreg, ®, &data); +} +OPTCMD_DEFINE_CMD_WITH_ARGS(putgpr, putgpr, (GPR, DATA)); +static int getnia(void) +{ + uint64_t reg = REG_NIA; return for_each_target("thread", getprocreg, ®, NULL); } +OPTCMD_DEFINE_CMD(getnia, getnia); -int handle_spr(int optind, int argc, char *argv[]) +static int putnia(uint64_t nia) { - char *endptr; - uint64_t spr; - - if (optind + 1 >= argc) { - printf("%s: command '%s' requires a GPR\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - spr = strtoull(argv[optind + 1], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse GPR '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } - - spr += REG_R31; - - if (strcmp(argv[optind], "putspr") == 0) { - uint64_t data; - - if (optind + 2 >= argc) { - printf("%s: command '%s' requires data\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - data = strtoull(argv[optind + 2], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse data '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } - - return for_each_target("thread", putprocreg, &spr, &data); - } - - return for_each_target("thread", getprocreg, &spr, NULL); + uint64_t reg = REG_NIA; + return for_each_target("thread", getprocreg, ®, &nia); } +OPTCMD_DEFINE_CMD_WITH_ARGS(putnia, putnia, (DATA)); -int handle_msr(int optind, int argc, char *argv[]) +static int getspr(int spr) { - uint64_t msr = REG_MSR; - char *endptr; - - if (strcmp(argv[optind], "putmsr") == 0) { - uint64_t data; - - if (optind + 1 >= argc) { - printf("%s: command '%s' requires data\n", argv[0], argv[optind]); - return -1; - } + uint64_t reg = spr + REG_R31; + return for_each_target("thread", getprocreg, ®, NULL); +} +OPTCMD_DEFINE_CMD_WITH_ARGS(getspr, getspr, (SPR)); - errno = 0; - data = strtoull(argv[optind + 1], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse data '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } +static int putspr(int spr, uint64_t data) +{ + uint64_t reg = spr + REG_R31; + return for_each_target("thread", putprocreg, ®, &data); +} +OPTCMD_DEFINE_CMD_WITH_ARGS(putspr, putspr, (SPR, DATA)); - return for_each_target("thread", putprocreg, &msr, &data); - } +static int getmsr(void) +{ + uint64_t reg = REG_MSR; + return for_each_target("thread", getprocreg, ®, NULL); +} +OPTCMD_DEFINE_CMD(getmsr, getmsr); - return for_each_target("thread", getprocreg, &msr, NULL); +static int putmsr(uint64_t data) +{ + uint64_t reg = REG_MSR; + return for_each_target("thread", putprocreg, ®, &data); } +OPTCMD_DEFINE_CMD_WITH_ARGS(putmsr, putmsr, (DATA)); diff --git a/src/reg.h b/src/reg.h deleted file mode 100644 index ad41d9d..0000000 --- a/src/reg.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2017 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -int handle_gpr(int optind, int argc, char *argv[]); -int handle_nia(int optind, int argc, char *argv[]); -int handle_spr(int optind, int argc, char *argv[]); -int handle_msr(int optind, int argc, char *argv[]); diff --git a/src/ring.c b/src/ring.c index b0c9376..58df4d1 100644 --- a/src/ring.c +++ b/src/ring.c @@ -18,11 +18,12 @@ #include #include #include +#include -#include -#include +#include #include "main.h" +#include "optcmd.h" static int pdbg_getring(struct pdbg_target *target, uint32_t index, uint64_t *addr, uint64_t *len) { @@ -51,31 +52,8 @@ static int pdbg_getring(struct pdbg_target *target, uint32_t index, uint64_t *ad return 1; } -int handle_getring(int optind, int argc, char *argv[]) +static int _getring(uint64_t ring_addr, uint64_t ring_len) { - uint64_t ring_addr, ring_len; - char *endptr; - - if (optind + 2 >= argc) { - printf("%s: command '%s' requires two arguments (address and length)\n", - argv[0], argv[optind]); - return -1; - } - - errno = 0; - ring_addr = strtoull(argv[optind + 1], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse ring address '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } - - ring_len = strtoull(argv[optind + 2], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse ring length '%s'\n", - argv[0], argv[optind], argv[optind + 2]); - return -1; - } - return for_each_target("chiplet", pdbg_getring, &ring_addr, &ring_len); } +OPTCMD_DEFINE_CMD_WITH_ARGS(getring, _getring, (ADDRESS, DATA)); diff --git a/src/ring.h b/src/ring.h deleted file mode 100644 index a72c875..0000000 --- a/src/ring.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright 2018 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -int handle_getring(int optind, int argc, char *argv[]); diff --git a/src/scom.c b/src/scom.c index 4c59e2a..2372e91 100644 --- a/src/scom.c +++ b/src/scom.c @@ -22,8 +22,9 @@ #include #include "main.h" +#include "optcmd.h" -static int getscom(struct pdbg_target *target, uint32_t index, uint64_t *addr, uint64_t *unused) +static int _getscom(struct pdbg_target *target, uint32_t index, uint64_t *addr, uint64_t *unused) { uint64_t value; @@ -35,7 +36,13 @@ static int getscom(struct pdbg_target *target, uint32_t index, uint64_t *addr, u return 1; } -static int putscom(struct pdbg_target *target, uint32_t index, uint64_t *addr, uint64_t *data) + int getscom(uint64_t addr) +{ + return for_each_target("pib", _getscom, &addr, NULL); +} +OPTCMD_DEFINE_CMD_WITH_ARGS(getscom, getscom, (ADDRESS)); + +static int _putscom(struct pdbg_target *target, uint32_t index, uint64_t *addr, uint64_t *data) { if (pib_write(target, *addr, *data)) return 0; @@ -43,44 +50,9 @@ static int putscom(struct pdbg_target *target, uint32_t index, uint64_t *addr, u return 1; } - -int handle_scoms(int optind, int argc, char *argv[]) + int putscom(uint64_t addr, uint64_t data, uint64_t mask) { - uint64_t addr; - char *endptr; - - if (optind + 1 >= argc) { - printf("%s: command '%s' requires an address\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - addr = strtoull(argv[optind + 1], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse address '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } - - if (strcmp(argv[optind], "putscom") == 0) { - uint64_t data; - - if (optind + 2 >= argc) { - printf("%s: command '%s' requires data\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - data = strtoull(argv[optind + 2], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse data '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } - - return for_each_target("pib", putscom, &addr, &data); - } - - return for_each_target("pib", getscom, &addr, NULL); + /* TODO: Restore the functionality */ + return for_each_target("pib", _putscom, &addr, &data); } - +OPTCMD_DEFINE_CMD_WITH_ARGS(putscom, putscom, (ADDRESS, DATA, DEFAULT_DATA("0xffffffffffffffff"))); diff --git a/src/scom.h b/src/scom.h deleted file mode 100644 index d4325b5..0000000 --- a/src/scom.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2017 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -int handle_scoms(int optind, int argc, char *argv[]); diff --git a/src/thread.c b/src/thread.c index e8b54cb..4b95636 100644 --- a/src/thread.c +++ b/src/thread.c @@ -21,7 +21,7 @@ #include #include "main.h" -#include "mem.h" +#include "optcmd.h" static int print_thread_status(struct pdbg_target *target, uint32_t index, uint64_t *arg, uint64_t *unused1) { @@ -81,6 +81,57 @@ static int print_core_thread_status(struct pdbg_target *core_target, uint32_t in return rc; } +static bool is_real_address(struct thread_regs *regs, uint64_t addr) +{ + return true; + if ((addr & 0xf000000000000000ULL) == 0xc000000000000000ULL) + return true; + return false; +} + +static int load8(struct pdbg_target *target, uint64_t addr, uint64_t *value) +{ + if (adu_getmem(target, addr, (uint8_t *)value, 8)) { + pdbg_log(PDBG_ERROR, "Unable to read memory address=%016" PRIx64 ".\n", addr); + return 0; + } + + return 1; +} + +static int dump_stack(struct thread_regs *regs) +{ + struct pdbg_target *target; + uint64_t sp = regs->gprs[1]; + uint64_t pc; + + pdbg_for_each_class_target("adu", target) { + if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED) + continue; + break; + } + + printf("STACK:\n"); + if (!target) + pdbg_log(PDBG_ERROR, "Unable to read memory (no ADU found)\n"); + + if (sp && is_real_address(regs, sp)) { + if (!load8(target, sp, &sp)) + return 1; + while (sp && is_real_address(regs, sp)) { + if (!load8(target, sp + 16, &pc)) + return 1; + + printf(" 0x%016" PRIx64 " 0x%16" PRIx64 "\n", sp, pc); + + if (!load8(target, sp, &sp)) + return 1; + } + } + + return 0; +} + static int get_thread_max_index(struct pdbg_target *target, uint32_t index, uint64_t *maxindex, uint64_t *unused) { if (index > *maxindex) @@ -140,48 +191,37 @@ static int state_thread(struct pdbg_target *thread_target, uint32_t index, uint6 return 1; } -int thread_start(int optind, int argc, char *argv[]) +static int thread_start(void) { return for_each_target("thread", start_thread, NULL, NULL); } +OPTCMD_DEFINE_CMD(start, thread_start); -int thread_step(int optind, int argc, char *argv[]) +static int thread_step(uint64_t count) { - uint64_t count; - char *endptr; - - if (optind + 1 >= argc) { - printf("%s: command '%s' requires a count\n", argv[0], argv[optind]); - return -1; - } - - errno = 0; - count = strtoull(argv[optind + 1], &endptr, 0); - if (errno || *endptr != '\0') { - printf("%s: command '%s' couldn't parse count '%s'\n", - argv[0], argv[optind], argv[optind + 1]); - return -1; - } - return for_each_target("thread", step_thread, &count, NULL); } +OPTCMD_DEFINE_CMD_WITH_ARGS(step, thread_step, (DATA)); -int thread_stop(int optind, int argc, char *argv[]) +static int thread_stop(void) { return for_each_target("thread", stop_thread, NULL, NULL); } +OPTCMD_DEFINE_CMD(stop, thread_stop); -int thread_status_print(int optind, int argc, char *argv[]) +static int thread_status_print(void) { return for_each_target("pib", print_proc_thread_status, NULL, NULL); } +OPTCMD_DEFINE_CMD(threadstatus, thread_status_print); -int thread_sreset(int optind, int argc, char *argv[]) +static int thread_sreset(void) { return for_each_target("thread", sreset_thread, NULL, NULL); } +OPTCMD_DEFINE_CMD(sreset, thread_sreset); -int thread_state(int optind, int argc, char *argv[]) +static int thread_state(void) { int err; @@ -191,3 +231,4 @@ int thread_state(int optind, int argc, char *argv[]) return err; } +OPTCMD_DEFINE_CMD(regs, thread_state); diff --git a/src/thread.h b/src/thread.h deleted file mode 100644 index 0c1caa2..0000000 --- a/src/thread.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright 2017 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -int thread_start(int optind, int argc, char *argv[]); -int thread_step(int optind, int argc, char *argv[]); -int thread_stop(int optind, int argc, char *argv[]); -int thread_status_print(int optind, int argc, char *argv[]); -int thread_sreset(int optind, int argc, char *argv[]); -int thread_state(int optind, int argc, char *argv[]);