diff options
| author | Amitay Isaacs <amitay@ozlabs.org> | 2018-11-16 12:14:19 +1100 |
|---|---|---|
| committer | Alistair Popple <alistair@popple.id.au> | 2018-11-16 15:31:40 +1100 |
| commit | b56e521ce1dda063379ad1be51670dff36726b08 (patch) | |
| tree | 49692cd9e04e99922b2223dc391a58406dea7269 | |
| parent | 7c78381f4b3f7890ff07204abebabe7fc76e38ab (diff) | |
| download | pdbg-b56e521ce1dda063379ad1be51670dff36726b08.tar.gz pdbg-b56e521ce1dda063379ad1be51670dff36726b08.zip | |
path: Add device tree path based targeting
Signed-off-by: Amitay Isaacs <amitay@ozlabs.org>
Reviewed-by: Alistair Popple <alistair@popple.id.au>
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | src/path.c | 332 | ||||
| -rw-r--r-- | src/path.h | 103 |
3 files changed, 437 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index c8f100e..2a687ca 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/pdbgproxy.c \ src/pdbgproxy.h \ src/progress.c \ diff --git a/src/path.c b/src/path.c new file mode 100644 index 0000000..6b4e29b --- /dev/null +++ b/src/path.c @@ -0,0 +1,332 @@ +/* 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 <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include <ctype.h> +#include <assert.h> +#include <limits.h> + +#include <libpdbg.h> + +#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); +} + +/* + * 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<path_target_count; i++) { + if (path_target[i] == prev) + return i; + } + + return -1; +} + +struct pdbg_target *path_target_find_next(const char *klass, int index) +{ + struct pdbg_target *target; + int i; + + for (i=index+1; i<path_target_count; i++) { + target = path_target[i]; + if (klass) { + const char *classname = pdbg_target_class_name(target); + + if (!strcmp(klass, classname)) + return target; + } else { + return target; + } + } + + return NULL; +} + +bool path_target_add(struct pdbg_target *target) +{ + int index; + + index = path_target_find(target); + if (index >= 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 comp_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(comp_name, sizeof(comp_name), pdbg_target_class_name(target)); + if (pats[level].match_full) { + tok = comp_name; + } else { + tok = strtok(comp_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<arg_count; i++) { + n = path_pattern_split(arg[i], pats); + if (n <= 0) + return false; + + path_pattern_match(pdbg_target_root(), pats, n, 0); + } + + return true; +} + +bool path_target_present(void) +{ + return (path_target_count > 0); +} + +bool path_target_selected(struct pdbg_target *target) +{ + int index; + + index = path_target_find(target); + if (index >= 0) + return true; + + return false; +} + +void path_target_dump(void) +{ + struct pdbg_target *target; + char *path; + + for_each_path_target(target) { + path = pdbg_target_path(target); + assert(path); + printf("%s\n", path); + free(path); + } +} + +struct pdbg_target *path_target_next(struct pdbg_target *prev) +{ + int index; + + index = path_target_find(prev); + return path_target_find_next(NULL, index); +} + +struct pdbg_target *path_target_next_class(const char *klass, + struct pdbg_target *prev) +{ + int index; + + index = path_target_find(prev); + return path_target_find_next(klass, index); +} diff --git a/src/path.h b/src/path.h new file mode 100644 index 0000000..c3c20c0 --- /dev/null +++ b/src/path.h @@ -0,0 +1,103 @@ +/* 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 <libpdbg.h> + +/** + * @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 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 + * @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); + +/** + * @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 + * @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); + +/** + * @brief Macro for iterating through all path targets + * + * target is of type struct pdbg_target + */ +#define for_each_path_target(target) \ + for (target = path_target_next(NULL); \ + target; \ + target = path_target_next(target)) + +/** + * @brief Macro for iterating through all path targets of specific class + * + * class is of type char * + * target is of type struct pdbg_target + */ +#define for_each_path_target_class(class, target) \ + for (target = path_target_next_class(class, NULL); \ + target; \ + target = path_target_next_class(class, target)) + +#endif |

