diff --git a/Makefile.am b/Makefile.am index 616030e37..7725b0e70 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,7 +11,8 @@ GIT_SHA1 ?= `git --work-tree=$(top_srcdir) --git-dir=$(top_srcdir)/.git describe libpdbg_tests = libpdbg_target_test \ libpdbg_probe_test1 \ libpdbg_probe_test2 \ - libpdbg_probe_test3 + libpdbg_probe_test3 \ + libpdbg_release_dt_root_test bin_PROGRAMS = pdbg check_PROGRAMS = $(libpdbg_tests) libpdbg_dtree_test \ @@ -249,6 +250,11 @@ libpdbg_target_test_CFLAGS = $(libpdbg_test_cflags) libpdbg_target_test_LDFLAGS = $(libpdbg_test_ldflags) libpdbg_target_test_LDADD = $(libpdbg_test_ldadd) +libpdbg_release_dt_root_test_SOURCES = src/tests/libpdbg_release_dt_root_test.c +libpdbg_release_dt_root_test_CFLAGS = $(libpdbg_test_cflags) +libpdbg_release_dt_root_test_LDFLAGS = $(libpdbg_test_ldflags) +libpdbg_release_dt_root_test_LDADD = $(libpdbg_test_ldadd) + libpdbg_probe_test1_SOURCES = src/tests/libpdbg_probe_test.c libpdbg_probe_test1_CFLAGS = $(libpdbg_test_cflags) -DTEST_ID=1 libpdbg_probe_test1_LDFLAGS = $(libpdbg_test_ldflags) diff --git a/libpdbg/device.c b/libpdbg/device.c index 494864df4..f33cce99f 100644 --- a/libpdbg/device.c +++ b/libpdbg/device.c @@ -708,8 +708,8 @@ static void pdbg_targets_init_virtual(struct pdbg_target *node, struct pdbg_targ * function deletes/removes a target form the list of associated * pdbg_target_class object. For internal use only. * - * @param target The pdbg_target object which will be removed from it's associated - * pdbg_target_class list + * @param target The pdbg_target object which will be removed from + * it's associated pdbg_target_class list * * @see pdbg_release_target for more details */ @@ -724,12 +724,12 @@ static void pdbg_del_target_from_target_class_list(struct pdbg_target* target) } /** - * @brief A function to delete/release an existing pdbg_target object along - * with its children from the node list/dev tree. Should be only called - * internally. Recursive in nature. For internal use only. + * @brief A function to delete/release an existing pdbg_target object + * along with its children from the node list/dev tree. Should + * be only called internally. Recursive in nature. * - * @param target The target node for which the children and then the node itself - * will be released/freed + * @param target The target node for which the children and then the + * node itself will be released/freed * * @see pdbg_release_dt_root for more details */ diff --git a/libpdbg/dtb.c b/libpdbg/dtb.c index 5c39d12e8..132ff132a 100644 --- a/libpdbg/dtb.c +++ b/libpdbg/dtb.c @@ -418,12 +418,6 @@ bool pdbg_set_backend(enum pdbg_backend backend, const char *backend_option) return false; } - if (pdbg_backend == backend) - { - pdbg_log(PDBG_ERROR, "New backend is same as the current backend. Not proceeding further\n"); - return false; - } - pdbg_backend = backend; pdbg_backend_option = backend_option; diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h index 18a688c75..2c8425246 100644 --- a/libpdbg/libpdbg.h +++ b/libpdbg/libpdbg.h @@ -1459,8 +1459,8 @@ bool pdbg_context_short(void); * switching the backend in the same process. It clears/releases the * existing dev tree (if any) children by children along with the root node. * - * Call this function very judiciously before ##pdbg_set_backend() if there is a - * dev tree already is in place and we are switching the backend + * Call this function very judiciously before ##pdbg_set_backend() if there + * is a dev tree already is in place and we are switching the backend */ void pdbg_release_dt_root(); diff --git a/src/tests/libpdbg_release_dt_root_test.c b/src/tests/libpdbg_release_dt_root_test.c new file mode 100644 index 000000000..d9a84e4cf --- /dev/null +++ b/src/tests/libpdbg_release_dt_root_test.c @@ -0,0 +1,358 @@ +/* Copyright 2023 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 + +static int count_target(struct pdbg_target *parent, const char *classname) +{ + struct pdbg_target *target = NULL; + int cnt = 0; + + pdbg_for_each_target(classname, parent, target) + ++cnt; + + return cnt; +} + +static int count_class_target(const char *classname) +{ + struct pdbg_target *target = NULL; + int cnt = 0; + + pdbg_for_each_class_target(classname, target) + ++cnt; + + return cnt; +} + +static int count_child_target(struct pdbg_target *parent) +{ + struct pdbg_target *child = NULL; + int cnt = 0; + + pdbg_for_each_child_target(parent, child) + ++cnt; + + return cnt; +} + +static void testClassCountTarget() +{ + int count = count_class_target("fsi"); + assert(count == 8); + + count = count_class_target("pib"); + assert(count == 8); + + count = count_class_target("core"); + assert(count == 32); + + count = count_class_target("thread"); + assert(count == 64); +} + +static void testSetTwo(struct pdbg_target *root) +{ + struct pdbg_target *parent, *target = NULL; + pdbg_for_each_child_target(root, parent) + { + const char *name = pdbg_target_dn_name(parent); + assert(strncmp(name, "proc", 4) == 0); + + pdbg_for_each_target("pib", parent, target) + { + name = pdbg_target_class_name(target); + assert(!strcmp(name, "pib")); + } + + pdbg_for_each_target("fsi", parent, target) + { + name = pdbg_target_class_name(target); + assert(!strcmp(name, "fsi")); + } + } +} + +static void testSetOne(struct pdbg_target *root, const bool dtreeReleased) +{ + if (dtreeReleased) + { + assert(!root); + return; + } + else + { + assert(root); + testClassCountTarget(); + } + testSetTwo(root); +} + +static void testFsiTarget() +{ + struct pdbg_target *parent, *target = NULL; + pdbg_for_each_class_target("fsi", target) + { + parent = pdbg_target_parent(NULL, target); + assert(parent); + + const char *name = pdbg_target_dn_name(parent); + assert(strncmp(name, "proc", 4) == 0); + + parent = pdbg_target_parent("fsi", target); + assert(parent == NULL); + + parent = pdbg_target_parent("pib", target); + assert(parent == NULL); + + parent = pdbg_target_parent("core", target); + assert(parent == NULL); + + parent = pdbg_target_parent("thread", target); + assert(parent == NULL); + + int count = count_child_target(target); + assert(count == 0); + + count = count_target(target, "fsi"); + assert(count == 1); + + count = count_target(target, "pib"); + assert(count == 0); + + count = count_target(target, "core"); + assert(count == 0); + + count = count_target(target, "thread"); + assert(count == 0); + + name = pdbg_target_name(target); + assert(!strcmp(name, "Fake FSI")); + + name = pdbg_target_class_name(target); + assert(!strcmp(name, "fsi")); + + name = pdbg_target_dn_name(target); + assert(!strncmp(name, "fsi", 3)); + } +} + +static void testPibTarget() +{ + struct pdbg_target *parent, *target = NULL; + pdbg_for_each_class_target("pib", target) + { + parent = pdbg_target_parent(NULL, target); + assert(parent); + + const char *name = pdbg_target_dn_name(parent); + assert(strncmp(name, "proc", 4) == 0); + + parent = pdbg_target_parent("fsi", target); + assert(parent == NULL); + + parent = pdbg_target_parent("pib", target); + assert(parent == NULL); + + parent = pdbg_target_parent("core", target); + assert(parent == NULL); + + parent = pdbg_target_parent("thread", target); + assert(parent == NULL); + + int count = count_child_target(target); + assert(count == 4); + + count = count_target(target, "fsi"); + assert(count == 0); + + count = count_target(target, "pib"); + assert(count == 1); + + count = count_target(target, "core"); + assert(count == 4); + + count = count_target(target, "thread"); + assert(count == 8); + + name = pdbg_target_name(target); + assert(!strcmp(name, "Fake PIB")); + + name = pdbg_target_class_name(target); + assert(!strcmp(name, "pib")); + + name = pdbg_target_dn_name(target); + assert(!strncmp(name, "pib", 3)); + } +} + +static void testCoreTarget() +{ + struct pdbg_target *parent, *target, *parent2 = NULL; + pdbg_for_each_class_target("core", target) + { + uint64_t addr, size; + uint32_t index; + + parent = pdbg_target_parent("fsi", target); + assert(parent == NULL); + + parent = pdbg_target_parent("pib", target); + assert(parent); + + parent2 = pdbg_target_require_parent("pib", target); + assert(parent == parent2); + + parent = pdbg_target_parent("core", target); + assert(parent == NULL); + + parent = pdbg_target_parent("thread", target); + assert(parent == NULL); + + int count = count_child_target(target); + assert(count == 2); + + count = count_target(target, "fsi"); + assert(count == 0); + + count = count_target(target, "pib"); + assert(count == 0); + + count = count_target(target, "core"); + assert(count == 1); + + count = count_target(target, "thread"); + assert(count == 2); + + const char *name = pdbg_target_name(target); + assert(!strcmp(name, "Fake Core")); + + name = pdbg_target_class_name(target); + assert(!strcmp(name, "core")); + + name = pdbg_target_dn_name(target); + assert(!strncmp(name, "core", 4)); + + index = pdbg_target_index(target); + addr = pdbg_target_address(target, &size); + assert(size == 0); + assert(addr == 0x10000 + (index + 1)*0x10); + } +} + +static void testThreadTarget() +{ + struct pdbg_target *parent, *target, *parent2 = NULL; + pdbg_for_each_class_target("thread", target) + { + parent = pdbg_target_parent("fsi", target); + assert(parent == NULL); + + parent = pdbg_target_parent("pib", target); + assert(parent); + + parent2 = pdbg_target_require_parent("pib", target); + assert(parent == parent2); + + parent = pdbg_target_parent("core", target); + assert(parent); + + parent2 = pdbg_target_require_parent("core", target); + assert(parent == parent2); + + parent = pdbg_target_parent("thread", target); + assert(parent == NULL); + + int count = count_child_target(target); + assert(count == 0); + + count = count_target(target, "fsi"); + assert(count == 0); + + count = count_target(target, "pib"); + assert(count == 0); + + count = count_target(target, "core"); + assert(count == 0); + + count = count_target(target, "thread"); + assert(count == 1); + + const char *name = pdbg_target_name(target); + assert(!strcmp(name, "Fake Thread")); + + name = pdbg_target_class_name(target); + assert(!strcmp(name, "thread")); + + name = pdbg_target_dn_name(target); + assert(!strncmp(name, "thread", 6)); + } +} + +static void testVariousTargets() +{ + testFsiTarget(); + testPibTarget(); + testCoreTarget(); + testThreadTarget(); +} + +int main(void) +{ + /** + * First set the backend to FAKE and inits the targets + * then test for various target counts for each class + * and other stuffs + */ + assert(pdbg_set_backend(PDBG_BACKEND_FAKE, NULL)); + assert(pdbg_targets_init(NULL)); + { + struct pdbg_target* root = pdbg_target_root(); + testSetOne(root, false); + testVariousTargets(); + + /** + * Now releases the device tree and check for root + * invalidation and subsequent tests + */ + { + pdbg_release_dt_root(); + root = pdbg_target_root(); + testSetOne(root, true); + } + } + /** + * Now again set the backend to FAKE one and inits the targets. + * Testing against the same set of conditions now should work as + * it did for earlier. Logic is if there in any leftover targets + * or target classes after releasing of device tree then the counts + * will be mismatched for the conditions set for a fresh device tree + */ + assert(pdbg_set_backend(PDBG_BACKEND_FAKE, NULL)); + assert(pdbg_targets_init(NULL)); + { + struct pdbg_target* root = pdbg_target_root(); + testSetOne(root, false); + testVariousTargets(); + } + + return 0; +}