diff options
author | Nick Alcock <nick.alcock@oracle.com> | 2024-06-11 20:58:00 +0100 |
---|---|---|
committer | Nick Alcock <nick.alcock@oracle.com> | 2024-06-18 13:20:32 +0100 |
commit | 2fa4b6e6df05990365066a0b286322502778d530 (patch) | |
tree | d4179f254df17ed689443abc326fc110f540293a /libctf/testsuite | |
parent | 1f62f2a9b561cd828feb719489be5dd5b9721777 (diff) | |
download | binutils-2fa4b6e6df05990365066a0b286322502778d530.zip binutils-2fa4b6e6df05990365066a0b286322502778d530.tar.gz binutils-2fa4b6e6df05990365066a0b286322502778d530.tar.bz2 |
libctf, include: new functions for looking up enumerators
Three new functions for looking up the enum type containing a given
enumeration constant, and optionally that constant's value.
The simplest, ctf_lookup_enumerator, looks up a root-visible enumerator by
name in one dict: if the dict contains multiple such constants (which is
possible for dicts created by older versions of the libctf deduplicator),
ECTF_DUPLICATE is returned.
The next simplest, ctf_lookup_enumerator_next, is an iterator which returns
all enumerators with a given name in a given dict, whether root-visible or
not.
The most elaborate, ctf_arc_lookup_enumerator_next, finds all
enumerators with a given name across all dicts in an entire CTF archive,
whether root-visible or not, starting looking in the shared parent dict;
opened dicts are cached (as with all other ctf_arc_*lookup functions) so
that repeated use does not incur repeated opening costs.
All three of these return enumerator values as int64_t: unfortunately, API
compatibility concerns prevent us from doing the same with the other older
enum-related functions, which all return enumerator constant values as ints.
We may be forced to add symbol-versioning compatibility aliases that fix the
other functions in due course, bumping the soname for platforms that do not
support such things.
ctf_arc_lookup_enumerator_next is implemented as a nested ctf_archive_next
iterator, and inside that, a nested ctf_lookup_enumerator_next iterator
within each dict. To aid in this, add support to ctf_next_t iterators for
iterators that are implemented in terms of two simultaneous nested iterators
at once. (It has always been possible for callers to use as many nested or
semi-overlapping ctf_next_t iterators as they need, which is one of the
advantages of this style over the _iter style that calls a function for each
thing iterated over: the iterator change here permits *ctf_next_t iterators
themselves* to be implemented by iterating using multiple other iterators as
part of their internal operation, transparently to the caller.)
Also add a testcase that tests all these functions (which is fairly easy
because ctf_arc_lookup_enumerator_next is implemented in terms of
ctf_lookup_enumerator_next) in addition to enumeration addition in
ctf_open()ed dicts, ctf_add_enumerator duplicate enumerator addition, and
conflicting enumerator constant deduplication.
include/
* ctf-api.h (ctf_lookup_enumerator): New.
(ctf_lookup_enumerator_next): Likewise.
(ctf_arc_lookup_enumerator_next): Likewise.
libctf/
* libctf.ver: Add them.
* ctf-impl.h (ctf_next_t) <ctn_next_inner>: New.
* ctf-util.c (ctf_next_copy): Copy it.
(ctf_next_destroy): Destroy it.
* ctf-lookup.c (ctf_lookup_enumerator): New.
(ctf_lookup_enumerator_next): New.
* ctf-archive.c (ctf_arc_lookup_enumerator_next): New.
* testsuite/libctf-lookup/enumerator-iteration.*: New test.
* testsuite/libctf-lookup/enum-ctf-2.c: New test CTF, used by the
above.
Diffstat (limited to 'libctf/testsuite')
-rw-r--r-- | libctf/testsuite/libctf-lookup/enum-ctf-2.c | 6 | ||||
-rw-r--r-- | libctf/testsuite/libctf-lookup/enumerator-iteration.c | 168 | ||||
-rw-r--r-- | libctf/testsuite/libctf-lookup/enumerator-iteration.lk | 17 |
3 files changed, 191 insertions, 0 deletions
diff --git a/libctf/testsuite/libctf-lookup/enum-ctf-2.c b/libctf/testsuite/libctf-lookup/enum-ctf-2.c new file mode 100644 index 0000000..39c9865 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/enum-ctf-2.c @@ -0,0 +1,6 @@ +enum e { ENUMSAMPLE_1 = 6, ENUMSAMPLE_2 = 7 }; + +enum ie2 { IENUMSAMPLE2_1 = -10, IENUMSAMPLE2_2 }; + +enum e baz; +enum ie2 quux; diff --git a/libctf/testsuite/libctf-lookup/enumerator-iteration.c b/libctf/testsuite/libctf-lookup/enumerator-iteration.c new file mode 100644 index 0000000..e46dad6 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/enumerator-iteration.c @@ -0,0 +1,168 @@ +/* Test enumerator iteration and querying. Because + ctf_arc_lookup_enumerator_next uses ctf_lookup_enumerator_next internally, we + only need to test the former. */ + +#include "config.h" +#include <ctf-api.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void +print_constants (ctf_archive_t *ctf, const char *name) +{ + ctf_next_t *i = NULL; + int err; + ctf_dict_t *fp; + ctf_id_t type; + int64_t val; + + while ((type = ctf_arc_lookup_enumerator_next (ctf, name, &i, + &val, &fp, &err)) != CTF_ERR) + { + char *foo; + + printf ("%s in %s has value %i\n", name, + foo = ctf_type_aname (fp, type), val); + free (foo); + + ctf_dict_close (fp); + } + if (err != ECTF_NEXT_END) + { + fprintf (stderr, "iteration failed: %s\n", ctf_errmsg (err)); + exit (1); + } +} + +int +main (int argc, char *argv[]) +{ + ctf_archive_t *ctf; + ctf_dict_t *fp; + int err; + ctf_id_t type; + ctf_next_t *i = NULL; + const char *name; + int64_t val; + int counter = 0; + + if (argc != 2) + { + fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]); + exit(1); + } + + if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL) + goto open_err; + + /* Look for all instances of ENUMSAMPLE2_1, and add some new enums to all + dicts found, to test dynamic enum iteration as well as static. + + Add two enums with a different name and constants to any that should + already be there (one hidden), and one with the same constants, but hidden, + to test ctf_lookup_enumerator_next()'s multiple-lookup functionality and + ctf_lookup_enumerator() in the presence of hidden types. */ + + printf ("First iteration: addition of enums.\n"); + while ((type = ctf_arc_lookup_enumerator_next (ctf, "IENUMSAMPLE2_2", &i, + &val, &fp, &err)) != CTF_ERR) + { + char *foo; + + printf ("IENUMSAMPLE2_2 in %s has value %i\n", + foo = ctf_type_aname (fp, type), val); + free (foo); + + if ((type = ctf_add_enum (fp, CTF_ADD_ROOT, "ie3")) == CTF_ERR) + goto enum_add_err; + + if (ctf_add_enumerator (fp, type, "DYNADD", counter += 10) < 0) + goto enumerator_add_err; + if (ctf_add_enumerator (fp, type, "DYNADD2", counter += 10) < 0) + goto enumerator_add_err; + + /* Make sure that overlapping enumerator addition fails as it should. */ + + if (ctf_add_enumerator (fp, type, "IENUMSAMPLE2_2", 666) >= 0 + || ctf_errno (fp) != ECTF_DUPLICATE) + fprintf (stderr, "Duplicate enumerator addition did not fail as it ought to\n"); + + if ((type = ctf_add_enum (fp, CTF_ADD_NONROOT, "ie4_hidden")) == CTF_ERR) + goto enum_add_err; + + if (ctf_add_enumerator (fp, type, "DYNADD3", counter += 10) < 0) + goto enumerator_add_err; + if (ctf_add_enumerator (fp, type, "DYNADD4", counter += 10) < 0) + goto enumerator_add_err; + + if ((type = ctf_add_enum (fp, CTF_ADD_NONROOT, "ie3_hidden")) == CTF_ERR) + goto enum_add_err; + + if (ctf_add_enumerator (fp, type, "DYNADD", counter += 10) < 0) + goto enumerator_add_err; + if (ctf_add_enumerator (fp, type, "DYNADD2", counter += 10) < 0) + goto enumerator_add_err; + + /* Look them up via ctf_lookup_enumerator. */ + + if (ctf_lookup_enumerator (fp, "DYNADD", &val) == CTF_ERR) + goto enumerator_lookup_err; + printf ("direct lookup: DYNADD value: %i\n", (int) val); + + if ((type = ctf_lookup_enumerator (fp, "DYNADD3", &val) != CTF_ERR) || + ctf_errno (fp) != ECTF_NOENUMNAM) + { + if (type != CTF_ERR) + { + char *foo; + printf ("direct lookup: hidden lookup did not return ECTF_NOENUMNAM but rather %i in %s\n", + val, foo = ctf_type_aname (fp, type)); + free (foo); + } + else + printf ("direct lookup: hidden lookup did not return ECTF_NOENUMNAM but rather %s\n", + ctf_errno (fp)); + } + + ctf_dict_close (fp); + } + if (err != ECTF_NEXT_END) + { + fprintf (stderr, "iteration failed: %s\n", ctf_errmsg (err)); + return 1; + } + + /* Look for (and print out) some enumeration constants. */ + + printf ("Second iteration: printing of enums.\n"); + + print_constants (ctf, "ENUMSAMPLE_1"); + print_constants (ctf, "IENUMSAMPLE_1"); + print_constants (ctf, "ENUMSAMPLE_2"); + print_constants (ctf, "DYNADD"); + print_constants (ctf, "DYNADD3"); + + ctf_close (ctf); + + printf ("All done.\n"); + + return 0; + + open_err: + fprintf (stderr, "%s: cannot open: %s\n", argv[0], ctf_errmsg (err)); + return 1; + enum_add_err: + fprintf (stderr, "Cannot add enum to dict \"%s\": %s\n", + ctf_cuname (fp) ? ctf_cuname (fp) : "(null: parent)", ctf_errmsg (ctf_errno (fp))); + return 1; + enumerator_add_err: + fprintf (stderr, "Cannot add enumerator to dict \"%s\": %s\n", + ctf_cuname (fp) ? ctf_cuname (fp) : "(null: parent)", ctf_errmsg (ctf_errno (fp))); + return 1; + enumerator_lookup_err: + fprintf (stderr, "Cannot look up enumerator in dict \"%s\": %s\n", + ctf_cuname (fp) ? ctf_cuname (fp) : "(null: parent)", ctf_errmsg (ctf_errno (fp))); + return 1; +} diff --git a/libctf/testsuite/libctf-lookup/enumerator-iteration.lk b/libctf/testsuite/libctf-lookup/enumerator-iteration.lk new file mode 100644 index 0000000..0c3cbfb --- /dev/null +++ b/libctf/testsuite/libctf-lookup/enumerator-iteration.lk @@ -0,0 +1,17 @@ +# lookup: enumerator-iteration.c +# source: enum-ctf.c +# source: enum-ctf-2.c +# link: on +First iteration: addition of enums. +IENUMSAMPLE2_2 in enum ie2 has value -9 +direct lookup: DYNADD value: 10 +Second iteration: printing of enums. +ENUMSAMPLE_1 in enum e has value 6 +ENUMSAMPLE_1 in enum e has value 0 +IENUMSAMPLE_1 in enum ie has value -10 +ENUMSAMPLE_2 in enum e has value 7 +ENUMSAMPLE_2 in enum e has value 1 +DYNADD in enum ie3 has value 10 +DYNADD in enum ie3_hidden has value 50 +DYNADD3 in enum ie4_hidden has value 30 +All done. |