| /* Make sure that errors are propagated properly from parent dicts to children | |
| when errors are encountered in child functions that can recurse to parents. | |
| We check specifically a subset of known-buggy functions. | |
| Functions that require a buggy linker to expose, or that only fail on | |
| assertion-failure-incurring corrupted dicts, are not tested. */ | |
| #include <ctf-api.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| static const char *desc; | |
| static void | |
| check_prop_err (ctf_dict_t *child, ctf_dict_t *parent, int expected) | |
| { | |
| if (ctf_errno (child) == expected) | |
| return; | |
| if (ctf_errno (parent) == expected) | |
| fprintf (stderr, "%s: error propagation failure: error \"%s\" not seen on child, " | |
| "but instead on parent\n", desc, ctf_errmsg (ctf_errno (parent))); | |
| else | |
| fprintf (stderr, "%s: expected error is entirely lost: " | |
| "\"%s\" seen on parent, \"%s\" on child\n", desc, | |
| ctf_errmsg (ctf_errno (parent)), | |
| ctf_errmsg (ctf_errno (child))); | |
| } | |
| static void | |
| no_prop_err (void) | |
| { | |
| fprintf (stderr, "%s: expected error return not observed.\n", desc); | |
| } | |
| int main (void) | |
| { | |
| ctf_dict_t *parent; | |
| ctf_dict_t *blank; | |
| ctf_dict_t *child; | |
| ctf_id_t void_id; | |
| ctf_id_t base; | |
| ctf_id_t slice; | |
| ctf_id_t function; | |
| ctf_encoding_t long_encoding = { CTF_INT_SIGNED, 0, sizeof (long) }; | |
| ctf_encoding_t void_encoding = { CTF_INT_SIGNED, 0, 0 }; | |
| ctf_encoding_t foo; | |
| ctf_funcinfo_t fi; | |
| ctf_id_t bar; | |
| char *funcname; | |
| int err; | |
| if ((parent = ctf_create (&err)) == NULL | |
| || (child = ctf_create (&err)) == NULL | |
| || (blank = ctf_create (&err)) == NULL) | |
| { | |
| fprintf (stderr, "Cannot create dicts: %s\n", ctf_errmsg (err)); | |
| return 1; | |
| } | |
| if ((ctf_import (child, parent)) < 0) | |
| { | |
| fprintf (stderr, "cannot import: %s\n", ctf_errmsg (ctf_errno (child))); | |
| return 1; | |
| } | |
| if ((void_id = ctf_add_integer (parent, CTF_ADD_ROOT, "void", &void_encoding)) | |
| == CTF_ERR) | |
| goto parent_err; | |
| if ((base = ctf_add_integer (parent, CTF_ADD_ROOT, "long int", &long_encoding)) | |
| == CTF_ERR) | |
| goto parent_err; | |
| foo.cte_format = 0; | |
| foo.cte_bits = 4; | |
| foo.cte_offset = 4; | |
| if ((slice = ctf_add_slice (child, CTF_ADD_ROOT, base, &foo)) == CTF_ERR) | |
| goto parent_err; | |
| if (ctf_add_variable (parent, "foo", base) < 0) | |
| goto child_err; | |
| fi.ctc_return = void_id; | |
| fi.ctc_argc = 0; | |
| fi.ctc_flags = 0; | |
| if ((function = ctf_add_function (child, CTF_ADD_ROOT, &fi, NULL)) == CTF_ERR) | |
| goto child_err; | |
| desc = "func info lookup of non-function"; | |
| if ((ctf_func_type_info (child, base, &fi)) != CTF_ERR) | |
| no_prop_err (); | |
| check_prop_err (child, parent, ECTF_NOTFUNC); | |
| desc = "func args lookup of non-function"; | |
| if ((ctf_func_type_args (child, base, 0, &bar)) != CTF_ERR) | |
| no_prop_err (); | |
| check_prop_err (child, parent, ECTF_NOTFUNC); | |
| if ((ctf_import (child, blank)) < 0) | |
| { | |
| fprintf (stderr, "cannot reimport: %s\n", ctf_errmsg (ctf_errno (child))); | |
| return 1; | |
| } | |
| /* This is testing ctf_type_resolve_unsliced(), which is called by the enum | |
| functions (which are not themselves buggy). This typea isn't an enum, but | |
| that's OK: we're after an error, after all, and the type we're slicing is | |
| not visible any longer, so nothing can tell it's not an enum. */ | |
| desc = "child slice resolution"; | |
| if ((ctf_enum_value (child, slice, "foo", NULL)) != CTF_ERR) | |
| no_prop_err (); | |
| check_prop_err (child, parent, ECTF_BADID); | |
| desc = "child slice encoding lookup"; | |
| if ((ctf_type_encoding (child, slice, &foo)) != CTF_ERR) | |
| no_prop_err (); | |
| check_prop_err (child, parent, ECTF_BADID); | |
| desc = "func info lookup of non-function"; | |
| if ((ctf_func_type_info (child, base, &fi)) != CTF_ERR) | |
| no_prop_err (); | |
| check_prop_err (child, parent, ECTF_BADID); | |
| desc = "func args lookup of non-function"; | |
| if ((ctf_func_type_args (child, base, 0, &bar)) != CTF_ERR) | |
| no_prop_err (); | |
| check_prop_err (child, parent, ECTF_BADID); | |
| desc = "child slice addition"; | |
| if ((slice = ctf_add_slice (child, CTF_ADD_ROOT, base, &foo)) != CTF_ERR) | |
| no_prop_err (); | |
| check_prop_err (child, parent, ECTF_BADID); | |
| desc = "variable lookup"; | |
| if (ctf_lookup_variable (child, "foo") != CTF_ERR) | |
| no_prop_err (); | |
| check_prop_err (child, parent, ECTF_NOTYPEDAT); | |
| desc = "function lookup via ctf_type_aname"; | |
| if ((funcname = ctf_type_aname (child, function)) != NULL) | |
| { | |
| no_prop_err (); | |
| free (funcname); | |
| } | |
| check_prop_err (child, parent, ECTF_BADID); | |
| ctf_dict_close (child); | |
| ctf_dict_close (parent); | |
| ctf_dict_close (blank); | |
| fprintf (stderr, "All done.\n"); | |
| return 0; | |
| parent_err: | |
| fprintf (stderr, "cannot populate parent: %s\n", ctf_errmsg (ctf_errno (parent))); | |
| return 1; | |
| child_err: | |
| fprintf (stderr, "cannot populate child: %s\n", ctf_errmsg (ctf_errno (parent))); | |
| return 1; | |
| } |