From patchwork Tue Oct 2 06:04:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amitay Isaacs X-Patchwork-Id: 977648 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 ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42PTNt3TkSz9sCw for ; Tue, 2 Oct 2018 16:13:34 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ozlabs.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; secure) header.d=ozlabs.org header.i=@ozlabs.org header.b="ko1ffGqs"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 42PTNt19WYzF3FL for ; Tue, 2 Oct 2018 16:13:34 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=ozlabs.org Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; secure) header.d=ozlabs.org header.i=@ozlabs.org header.b="ko1ffGqs"; dkim-atps=neutral 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 42PTBc0ZP6zF3D0 for ; Tue, 2 Oct 2018 16:04:40 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=ozlabs.org Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=ozlabs.org header.i=@ozlabs.org header.b="ko1ffGqs"; dkim-atps=neutral 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 42PTBb4PX8z9sj1; Tue, 2 Oct 2018 16:04:39 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ozlabs.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ozlabs.org; s=201707; t=1538460279; bh=AsIKxBA76/CxUTsithleZHfbEYjAaeXNMkBap4dfl9c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ko1ffGqslvp0KYksIzIOAnWlXY2W8dxM27CLMwl9rl3WHp7ZnOKiwKfgQPdQ805cF LF80rsrC+4CSQsWAo07lUxUL4imCoOr+dg82aYmIg/4HyRNmwb9Bwn7tFDMOyWJcAB vMW2xBYBK00RM/qL9TsCJ8YL2PAwb/mAoTP9i+mKXffWn9bVRVBzSnj1DakGdyYH13 oPwk5wvAaJNZOdLvnIb4/cCCK8r1TDyZTo3ONB4ZXkPleDFt4asfLAs/0UpvbaHN1A 7cLJwrBCW5cd67sFT9XrMuzcb9NQO/NVVVwjHj5DDAd9wLf2kjtx+xg8KTBe6RYAoO UUWCcyWUVEXog== From: Amitay Isaacs To: pdbg@lists.ozlabs.org Date: Tue, 2 Oct 2018 16:04:25 +1000 Message-Id: <20181002060430.3344784-5-amitay@ozlabs.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181002060430.3344784-1-amitay@ozlabs.org> References: <20181002060430.3344784-1-amitay@ozlabs.org> Subject: [Pdbg] [PATCH 04/10] path: Add device tree path based targeting X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Amitay Isaacs MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" Signed-off-by: Amitay Isaacs --- Makefile.am | 2 + src/path.c | 383 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/path.h | 125 +++++++++++++++++ 3 files changed, 510 insertions(+) create mode 100644 src/path.c create mode 100644 src/path.h diff --git a/Makefile.am b/Makefile.am index 8bf2ba0..653b7d9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -78,6 +78,8 @@ pdbg_SOURCES = \ src/options.h \ src/parsers.c \ src/parsers.h \ + src/path.c \ + src/path.h \ src/progress.c \ src/progress.h \ src/reg.c \ diff --git a/src/path.c b/src/path.c new file mode 100644 index 0000000..66098bc --- /dev/null +++ b/src/path.c @@ -0,0 +1,383 @@ +/* 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. + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "path.h" +#include "util.h" + +#define MAX_PATH_COMP_LEN 32 +#define MAX_PATH_COMPONENTS 16 +#define MAX_PATH_LEN (MAX_PATH_COMP_LEN * MAX_PATH_COMPONENTS) + +/* This is max(MAX_PROCESSORS, MAX_CHIPS, MAX_THREADS) */ +#define MAX_PATH_INDEX 64 + +struct path_pattern { + char prefix[MAX_PATH_COMP_LEN]; + int index[MAX_PATH_INDEX]; + bool match_full; + bool match_index; +}; + +/* Start with max threads, rather than defining arbitrary number */ +#define MAX_TARGETS (64 * 24 * 8) + +static struct pdbg_target *path_target[MAX_TARGETS]; +static unsigned int path_target_count; + +static void safe_strcpy(char *dest, size_t n, const char *src) +{ + assert(strlen(src) + 1 <= n); + + strcpy(dest, src); +} + +static void safe_strcat(char *dest, size_t n, const char *src) +{ + assert(strlen(dest) + strlen(src) + 1 <= n); + + strcat(dest, src); +} + +/* + * Parse string components of following forms: + * pib0 + * core[1-3,11-13] + * thread* + * adu@123000 + */ +static bool path_pattern_parse(const char *arg, struct path_pattern *pat) +{ + char tmp[strlen(arg)+1]; + char *tok; + bool ok; + + safe_strcpy(tmp, sizeof(tmp), arg); + + memset(pat, 0, sizeof(*pat)); + + if (strchr(tmp, '@')) { + safe_strcpy(pat->prefix, sizeof(pat->prefix), tmp); + pat->match_full = true; + + } else if (strchr(tmp, '*')) { + tok = strtok(tmp, "*"); + if (!tok) + safe_strcpy(pat->prefix, sizeof(pat->prefix), "all"); + else + safe_strcpy(pat->prefix, sizeof(pat->prefix), tok); + + } else if (strchr(tmp, '[')) { + tok = strtok(tmp, "["); + if (tok == NULL) { + fprintf(stderr, "Invalid pattern '%s'\n", arg); + return false; + } + safe_strcpy(pat->prefix, sizeof(pat->prefix), tok); + + tok = strtok(NULL, "]"); + if (!tok) { + fprintf(stderr, "Invalid pattern '%s'\n", arg); + return false; + } + + ok = parse_list(tok, MAX_PATH_INDEX, pat->index, NULL); + if (!ok) + return false; + + pat->match_index = true; + + } else { + size_t n = strlen(tmp) - 1; + while (n >= 0 && isdigit(tmp[n])) + n--; + n++; + + if (n != strlen(tmp)) { + int index; + + index = atoi(&tmp[n]); + if (index < 0 || index >= MAX_PATH_INDEX) { + fprintf(stderr, "Invalid index '%s'\n", &tmp[n]); + return false; + } + tmp[n] = '\0'; + pat->index[index] = 1; + pat->match_index = true; + } + + safe_strcpy(pat->prefix, sizeof(pat->prefix), tmp); + } + + if (!pat->prefix) + return false; + + return true; +} + +static int path_pattern_split(const char *arg, struct path_pattern *pats) +{ + char arg_copy[MAX_PATH_LEN]; + char *tmp, *tok, *saveptr = NULL; + int n; + bool ok; + + safe_strcpy(arg_copy, sizeof(arg_copy), arg); + + tmp = arg_copy; + n = 0; + while ((tok = strtok_r(tmp, "/", &saveptr))) { + size_t len = strlen(tok); + + if (len == 0) + continue; + + if (len >= MAX_PATH_LEN) { + fprintf(stderr, "Pattern component '%s' too long\n", tok); + return -1; + } + + ok = path_pattern_parse(tok, &pats[n]); + if (!ok) + return -1; + + n++; + assert(n <= MAX_PATH_COMPONENTS); + + tmp = NULL; + } + + return n; +} + +static int path_target_find(struct pdbg_target *prev) +{ + int i; + + if (!prev) + return -1; + + for (i=0; i= 0) + return true; + + if (path_target_count == MAX_TARGETS) + return false; + + path_target[path_target_count] = target; + path_target_count++; + return true; +} + +static void path_pattern_match(struct pdbg_target *target, + struct path_pattern *pats, + int max_levels, + int level) +{ + struct pdbg_target *child; + char dn_name[MAX_PATH_COMP_LEN]; + char *tok; + int next = level; + bool found = false; + + if (target == pdbg_target_root()) { + goto end; + } + + if (!strcmp("all", pats[level].prefix)) { + if (!path_target_add(target)) + return; + goto end; + } + + safe_strcpy(dn_name, sizeof(dn_name), pdbg_target_dn_name(target)); + if (pats[level].match_full) { + tok = dn_name; + } else { + tok = strtok(dn_name, "@"); + } + + if (!strcmp(tok, pats[level].prefix)) { + found = true; + + if (pats[level].match_index) { + int index = pdbg_target_index(target); + + if (pats[level].index[index] != 1) + found = false; + } + } + + if (found) { + if (level == max_levels-1) { + path_target_add(target); + return; + } else { + next = level + 1; + } + } + +end: + pdbg_for_each_child_target(target, child) { + path_pattern_match(child, pats, max_levels, next); + } +} + +bool path_target_parse(const char **arg, int arg_count) +{ + struct path_pattern pats[MAX_PATH_COMPONENTS]; + int i, n; + + for (i=0; i 0); +} + +bool path_target_selected(struct pdbg_target *target) +{ + int index; + + index = path_target_find(target); + if (index >= 0) + return true; + + return false; +} + +static void path_target_build_path(struct pdbg_target *target, char *path, size_t len) +{ + char dn_name[MAX_PATH_LEN], *tok; + char number[16]; + int index; + + if (target != pdbg_target_root()) { + path_target_build_path(pdbg_target_parent(NULL, target), path, len); + index = pdbg_target_index(target); + if (index != -1) { + safe_strcpy(dn_name, sizeof(dn_name), pdbg_target_dn_name(target)); + tok = strtok(dn_name, "@"); + sprintf(number, "%d", index); + safe_strcat(path, len, "/"); + safe_strcat(path, len, tok); + safe_strcat(path, len, number); + } else { + safe_strcat(path, len, "/"); + safe_strcat(path, len, pdbg_target_dn_name(target)); + } + } else { + safe_strcpy(path, len, ""); + } +} + +char *path_target_path(struct pdbg_target *target) +{ + char path[MAX_PATH_LEN]; + + path_target_build_path(target, path, sizeof(path)); + return strdup(path); +} + +void path_target_dump(void) +{ + struct pdbg_target *target; + char *path; + + for_each_path_target(target, false) { + path = path_target_path(target); + assert(path); + printf("%s\n", path); + free(path); + } +} + +struct pdbg_target *path_target_next(struct pdbg_target *prev, + bool only_enabled) +{ + int index; + + index = path_target_find(prev); + return path_target_find_next(NULL, index, only_enabled); +} + +struct pdbg_target *path_target_next_class(const char *klass, + struct pdbg_target *prev, + bool only_enabled) +{ + int index; + + index = path_target_find(prev); + return path_target_find_next(klass, index, only_enabled); +} diff --git a/src/path.h b/src/path.h new file mode 100644 index 0000000..35c3a6e --- /dev/null +++ b/src/path.h @@ -0,0 +1,125 @@ +/* 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. + */ +#ifndef __PDBG_PATH_H +#define __PDBG_PATH_H + +#include + +/** + * @brief Parse a list of path target strings + * + * @param[in] arg An array of strings + * @param[in] arg_count The number of strings + * @return true on success, false on error + */ +bool path_target_parse(const char **arg, int arg_count); + +/** + * @brief Check if there are any path targets + * + * @return true if number of path targets > 0, false otherwise + */ +bool path_target_present(void); + +/** + * @brief Add a target to the list + * + * @param[in] target pdbg target + * @return true on success, false on error + */ +bool path_target_add(struct pdbg_target *target); + +/** + * @brief Check if the specified target is selected + * + * @param[in] target pdbg target + * @return true if the target is selected, false otherwise + */ +bool path_target_selected(struct pdbg_target *target); + +/** + * @brief Get the device-tree path for a target + * + * @param[in] target pdbg target + * @return path for the target, NULL on error + * + * The path is allocated by malloc and should be freed by caller. + */ +char *path_target_path(struct pdbg_target *target); + +/** + * @brief Print the list of path targets to stdout + */ +void path_target_dump(void); + +/** + * @brief Iterator for list of path targets + * + * @param[in] prev The last pdbg target + * @param[in] only_enabled Whether to list enabled targets or all + * @return the next pdbg target in the list, NULL otherwise + * + * If prev is NULL, then return the first pdbg target in the list. + * If there are no more pdbg targets in the list, NULL is returned. + */ +struct pdbg_target *path_target_next(struct pdbg_target *prev, + bool only_enabled); + +/** + * @brief Iterator for a list of path targets of specified class + * + * @param[in] klass The class of the targets required + * @param[in] prev The last pdbg target + * @param[in] only_enabled Whether to list enabled targets or all + * @return the next matching pdbg target in the list, NULL otherwise + * + * If prev is NULL, then return the first matching pdbg target in the list. + * If there are no more matching pdbg targets, NULL is returned. + */ +struct pdbg_target *path_target_next_class(const char *klass, + struct pdbg_target *prev, + bool only_enabled); + +/** + * @brief Macro for iterating through all path targets + * + * target is of type struct pdbg_target + * only_eanbled is boolean + * + * If only_enabled is true, iterate through targets that are enabled; + * otherwise iterate through all targets + */ +#define for_each_path_target(target, only_enabled) \ + for (target = path_target_next(NULL, only_enabled); \ + target; \ + target = path_target_next(target, only_enabled)) + +/** + * @brief Macro for iterating through all path targets of specific class + * + * class is of type char * + * target is of type struct pdbg_target + * only_eanbled is boolean + * + * If only_enabled is true, iterate through targets that are enabled; + * otherwise iterate through all targets + */ +#define for_each_path_target_class(class, target, only_enabled) \ + for (target = path_target_next_class(class, NULL, only_enabled); \ + target; \ + target = path_target_next_class(class, target, only_enabled)) + +#endif