/* 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 #include #include #include 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; }