aarch64: rcpc3: Add +rcpc3 architectural feature support flag
[platform/upstream/binutils.git] / libbacktrace / mtest.c
1 /* mtest.c -- Minidebug test for libbacktrace library
2    Copyright (C) 2020-2021 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor, Google.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9     (1) Redistributions of source code must retain the above copyright
10     notice, this list of conditions and the following disclaimer.
11
12     (2) Redistributions in binary form must reproduce the above copyright
13     notice, this list of conditions and the following disclaimer in
14     the documentation and/or other materials provided with the
15     distribution.
16
17     (3) The name of the author may not be used to
18     endorse or promote products derived from this software without
19     specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.  */
32
33 /* This program tests using libbacktrace with a program that uses the
34    minidebuginfo format in a .gnu_debugdata section.  See
35    https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html
36    for a bit more information about minidebuginfo.  What is relevant
37    for libbacktrace is that we have just a symbol table, with no debug
38    info, so we should be able to do a function backtrace, but we can't
39    do a file/line backtrace.  */
40
41 #include <assert.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include "backtrace.h"
46 #include "backtrace-supported.h"
47
48 #include "testlib.h"
49
50 static int test1 (void) __attribute__ ((noinline, noclone, unused));
51 static int f2 (int) __attribute__ ((noinline, noclone));
52 static int f3 (int, int) __attribute__ ((noinline, noclone));
53
54 /* Collected PC values.  */
55
56 static uintptr_t addrs[20];
57
58 /* The backtrace callback function.  This is like callback_one in
59    testlib.c, but it saves the PC also.  */
60
61 static int
62 callback_mtest (void *vdata, uintptr_t pc, const char *filename, int lineno,
63                 const char *function)
64 {
65   struct bdata *data = (struct bdata *) vdata;
66
67   if (data->index >= sizeof addrs / sizeof addrs[0])
68     {
69       fprintf (stderr, "callback_mtest: callback called too many times\n");
70       data->failed = 1;
71       return 1;
72     }
73
74   addrs[data->index] = pc;
75
76   return callback_one (vdata, pc, filename, lineno, function);
77 }
78
79 /* Test the backtrace function with non-inlined functions.  (We don't
80    test with inlined functions because they won't work with minidebug
81    anyhow.)  */
82
83 static int
84 test1 (void)
85 {
86   /* Returning a value here and elsewhere avoids a tailcall which
87      would mess up the backtrace.  */
88   return f2 (__LINE__) + 1;
89 }
90
91 static int
92 f2 (int f1line)
93 {
94   return f3 (f1line, __LINE__) + 2;
95 }
96
97 static int
98 f3 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
99 {
100   struct info all[20];
101   struct bdata data;
102   int i;
103   size_t j;
104
105   data.all = &all[0];
106   data.index = 0;
107   data.max = 20;
108   data.failed = 0;
109
110   i = backtrace_full (state, 0, callback_mtest, error_callback_one, &data);
111
112   if (i != 0)
113     {
114       fprintf (stderr, "test1: unexpected return value %d\n", i);
115       data.failed = 1;
116     }
117
118   if (data.index < 3)
119     {
120       fprintf (stderr,
121                "test1: not enough frames; got %zu, expected at least 3\n",
122                data.index);
123       data.failed = 1;
124     }
125
126   /* When using minidebug we don't expect the function name here.  */
127
128   for (j = 0; j < 3 && j < data.index; j++)
129     {
130       if (all[j].function == NULL)
131         {
132           struct symdata symdata;
133
134           symdata.name = NULL;
135           symdata.val = 0;
136           symdata.size = 0;
137           symdata.failed = 0;
138
139           i = backtrace_syminfo (state, addrs[j], callback_three,
140                                  error_callback_three, &symdata);
141           if (i == 0)
142             {
143               fprintf (stderr,
144                        ("test1: [%zu], unexpected return value from "
145                         "backtrace_syminfo %d\n"),
146                        j, i);
147               data.failed = 1;
148             }
149           else if (symdata.name == NULL)
150             {
151               fprintf (stderr, "test1: [%zu]: syminfo did not find name\n", j);
152               data.failed = 1;
153             }
154           else
155             all[j].function = strdup (symdata.name);
156         }
157     }
158
159   if (data.index > 0)
160     {
161       if (all[0].function == NULL)
162         {
163           fprintf (stderr, "test1: [0]: missing function name\n");
164           data.failed = 1;
165         }
166       else if (strcmp (all[0].function, "f3") != 0)
167         {
168           fprintf (stderr, "test1: [0]: got %s expected %s\n",
169                    all[0].function, "f3");
170           data.failed = 1;
171         }
172     }
173
174   if (data.index > 1)
175     {
176       if (all[1].function == NULL)
177         {
178           fprintf (stderr, "test1: [1]: missing function name\n");
179           data.failed = 1;
180         }
181       else if (strcmp (all[1].function, "f2") != 0)
182         {
183           fprintf (stderr, "test1: [1]: got %s expected %s\n",
184                    all[0].function, "f2");
185           data.failed = 1;
186         }
187     }
188
189   if (data.index > 2)
190     {
191       if (all[2].function == NULL)
192         {
193           fprintf (stderr, "test1: [2]: missing function name\n");
194           data.failed = 1;
195         }
196       else if (strcmp (all[2].function, "test1") != 0)
197         {
198           fprintf (stderr, "test1: [2]: got %s expected %s\n",
199                    all[0].function, "test1");
200           data.failed = 1;
201         }
202     }
203
204   printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
205
206   if (data.failed)
207     ++failures;
208
209   return failures;
210 }
211
212 /* Test the backtrace_simple function with non-inlined functions.  */
213
214 static int test3 (void) __attribute__ ((noinline, noclone, unused));
215 static int f22 (int) __attribute__ ((noinline, noclone));
216 static int f23 (int, int) __attribute__ ((noinline, noclone));
217
218 static int
219 test3 (void)
220 {
221   return f22 (__LINE__) + 1;
222 }
223
224 static int
225 f22 (int f1line)
226 {
227   return f23 (f1line, __LINE__) + 2;
228 }
229
230 static int
231 f23 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
232 {
233   uintptr_t addrs[20];
234   struct sdata data;
235   int i;
236
237   data.addrs = &addrs[0];
238   data.index = 0;
239   data.max = 20;
240   data.failed = 0;
241
242   i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
243
244   if (i != 0)
245     {
246       fprintf (stderr, "test3: unexpected return value %d\n", i);
247       data.failed = 1;
248     }
249
250   if (!data.failed)
251     {
252       int j;
253
254       for (j = 0; j < 3; ++j)
255         {
256           struct symdata symdata;
257
258           symdata.name = NULL;
259           symdata.val = 0;
260           symdata.size = 0;
261           symdata.failed = 0;
262
263           i = backtrace_syminfo (state, addrs[j], callback_three,
264                                  error_callback_three, &symdata);
265           if (i == 0)
266             {
267               fprintf (stderr,
268                        ("test3: [%d]: unexpected return value "
269                         "from backtrace_syminfo %d\n"),
270                        j, i);
271               symdata.failed = 1;
272             }
273
274           if (!symdata.failed)
275             {
276               const char *expected;
277
278               switch (j)
279                 {
280                 case 0:
281                   expected = "f23";
282                   break;
283                 case 1:
284                   expected = "f22";
285                   break;
286                 case 2:
287                   expected = "test3";
288                   break;
289                 default:
290                   assert (0);
291                 }
292
293               if (symdata.name == NULL)
294                 {
295                   fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
296                   symdata.failed = 1;
297                 }
298               /* Use strncmp, not strcmp, because GCC might create a
299                  clone.  */
300               else if (strncmp (symdata.name, expected, strlen (expected))
301                        != 0)
302                 {
303                   fprintf (stderr,
304                            ("test3: [%d]: unexpected syminfo name "
305                             "got %s expected %s\n"),
306                            j, symdata.name, expected);
307                   symdata.failed = 1;
308                 }
309             }
310
311           if (symdata.failed)
312             data.failed = 1;
313         }
314     }
315
316   printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
317
318   if (data.failed)
319     ++failures;
320
321   return failures;
322 }
323
324 int test5 (void) __attribute__ ((unused));
325
326 int global = 1;
327
328 int
329 test5 (void)
330 {
331   struct symdata symdata;
332   int i;
333   uintptr_t addr = (uintptr_t) &global;
334
335   if (sizeof (global) > 1)
336     addr += 1;
337
338   symdata.name = NULL;
339   symdata.val = 0;
340   symdata.size = 0;
341   symdata.failed = 0;
342
343   i = backtrace_syminfo (state, addr, callback_three,
344                          error_callback_three, &symdata);
345   if (i == 0)
346     {
347       fprintf (stderr,
348                "test5: unexpected return value from backtrace_syminfo %d\n",
349                i);
350       symdata.failed = 1;
351     }
352
353   if (!symdata.failed)
354     {
355       if (symdata.name == NULL)
356         {
357           fprintf (stderr, "test5: NULL syminfo name\n");
358           symdata.failed = 1;
359         }
360       else if (!(strncmp (symdata.name, "global", 6) == 0
361                  && (symdata.name[6] == '\0'|| symdata.name[6] == '.')))
362         {
363           fprintf (stderr,
364                    "test5: unexpected syminfo name got %s expected %s\n",
365                    symdata.name, "global");
366           symdata.failed = 1;
367         }
368       else if (symdata.val != (uintptr_t) &global)
369         {
370           fprintf (stderr,
371                    "test5: unexpected syminfo value got %lx expected %lx\n",
372                    (unsigned long) symdata.val,
373                    (unsigned long) (uintptr_t) &global);
374           symdata.failed = 1;
375         }
376       else if (symdata.size != sizeof (global))
377         {
378           fprintf (stderr,
379                    "test5: unexpected syminfo size got %lx expected %lx\n",
380                    (unsigned long) symdata.size,
381                    (unsigned long) sizeof (global));
382           symdata.failed = 1;
383         }
384     }
385
386   printf ("%s: backtrace_syminfo variable\n",
387           symdata.failed ? "FAIL" : "PASS");
388
389   if (symdata.failed)
390     ++failures;
391
392   return failures;
393 }
394
395 int
396 main (int argc ATTRIBUTE_UNUSED, char **argv)
397 {
398   state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
399                                   error_callback_create, NULL);
400
401 #if BACKTRACE_SUPPORTED
402   test1 ();
403   test3 ();
404 #if BACKTRACE_SUPPORTS_DATA
405   test5 ();
406 #endif
407 #endif
408
409   exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
410 }