aboutsummaryrefslogtreecommitdiff
path: root/libctf/testsuite/libctf-writable/error-propagation.c
blob: 9d25e635c85e699fc328dc1cb02e6c938476a1d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* 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;

}