Support x86 Intel MSR_IMM
[binutils-gdb.git] / libbacktrace / mtest.c
blob9afe708951483de99a5e08aefe4601960116b8f0
1 /* mtest.c -- Minidebug test for libbacktrace library
2 Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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.
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.
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. */
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. */
41 #include <assert.h>
42 #include <stdlib.h>
43 #include <string.h>
45 #include "backtrace.h"
46 #include "backtrace-supported.h"
48 #include "testlib.h"
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));
54 /* Collected PC values. */
56 static uintptr_t addrs[20];
58 /* The backtrace callback function. This is like callback_one in
59 testlib.c, but it saves the PC also. */
61 static int
62 callback_mtest (void *vdata, uintptr_t pc, const char *filename, int lineno,
63 const char *function)
65 struct bdata *data = (struct bdata *) vdata;
67 if (data->index >= sizeof addrs / sizeof addrs[0])
69 fprintf (stderr, "callback_mtest: callback called too many times\n");
70 data->failed = 1;
71 return 1;
74 addrs[data->index] = pc;
76 return callback_one (vdata, pc, filename, lineno, function);
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.) */
83 static int
84 test1 (void)
86 /* Returning a value here and elsewhere avoids a tailcall which
87 would mess up the backtrace. */
88 return f2 (__LINE__) + 1;
91 static int
92 f2 (int f1line)
94 return f3 (f1line, __LINE__) + 2;
97 static int
98 f3 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
100 struct info all[20];
101 struct bdata data;
102 int i;
103 size_t j;
105 data.all = &all[0];
106 data.index = 0;
107 data.max = 20;
108 data.failed = 0;
110 i = backtrace_full (state, 0, callback_mtest, error_callback_one, &data);
112 if (i != 0)
114 fprintf (stderr, "test1: unexpected return value %d\n", i);
115 data.failed = 1;
118 if (data.index < 3)
120 fprintf (stderr,
121 "test1: not enough frames; got %zu, expected at least 3\n",
122 data.index);
123 data.failed = 1;
126 /* When using minidebug we don't expect the function name here. */
128 for (j = 0; j < 3 && j < data.index; j++)
130 if (all[j].function == NULL)
132 struct symdata symdata;
134 symdata.name = NULL;
135 symdata.val = 0;
136 symdata.size = 0;
137 symdata.failed = 0;
139 i = backtrace_syminfo (state, addrs[j], callback_three,
140 error_callback_three, &symdata);
141 if (i == 0)
143 fprintf (stderr,
144 ("test1: [%zu], unexpected return value from "
145 "backtrace_syminfo %d\n"),
146 j, i);
147 data.failed = 1;
149 else if (symdata.name == NULL)
151 fprintf (stderr, "test1: [%zu]: syminfo did not find name\n", j);
152 data.failed = 1;
154 else
155 all[j].function = strdup (symdata.name);
159 if (data.index > 0)
161 if (all[0].function == NULL)
163 fprintf (stderr, "test1: [0]: missing function name\n");
164 data.failed = 1;
166 else if (strcmp (all[0].function, "f3") != 0)
168 fprintf (stderr, "test1: [0]: got %s expected %s\n",
169 all[0].function, "f3");
170 data.failed = 1;
174 if (data.index > 1)
176 if (all[1].function == NULL)
178 fprintf (stderr, "test1: [1]: missing function name\n");
179 data.failed = 1;
181 else if (strcmp (all[1].function, "f2") != 0)
183 fprintf (stderr, "test1: [1]: got %s expected %s\n",
184 all[0].function, "f2");
185 data.failed = 1;
189 if (data.index > 2)
191 if (all[2].function == NULL)
193 fprintf (stderr, "test1: [2]: missing function name\n");
194 data.failed = 1;
196 else if (strcmp (all[2].function, "test1") != 0)
198 fprintf (stderr, "test1: [2]: got %s expected %s\n",
199 all[0].function, "test1");
200 data.failed = 1;
204 printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
206 if (data.failed)
207 ++failures;
209 return failures;
212 /* Test the backtrace_simple function with non-inlined functions. */
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));
218 static int
219 test3 (void)
221 return f22 (__LINE__) + 1;
224 static int
225 f22 (int f1line)
227 return f23 (f1line, __LINE__) + 2;
230 static int
231 f23 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
233 uintptr_t addrs[20];
234 struct sdata data;
235 int i;
237 data.addrs = &addrs[0];
238 data.index = 0;
239 data.max = 20;
240 data.failed = 0;
242 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
244 if (i != 0)
246 fprintf (stderr, "test3: unexpected return value %d\n", i);
247 data.failed = 1;
250 if (!data.failed)
252 int j;
254 for (j = 0; j < 3; ++j)
256 struct symdata symdata;
258 symdata.name = NULL;
259 symdata.val = 0;
260 symdata.size = 0;
261 symdata.failed = 0;
263 i = backtrace_syminfo (state, addrs[j], callback_three,
264 error_callback_three, &symdata);
265 if (i == 0)
267 fprintf (stderr,
268 ("test3: [%d]: unexpected return value "
269 "from backtrace_syminfo %d\n"),
270 j, i);
271 symdata.failed = 1;
274 if (!symdata.failed)
276 const char *expected;
278 switch (j)
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);
293 if (symdata.name == NULL)
295 fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
296 symdata.failed = 1;
298 /* Use strncmp, not strcmp, because GCC might create a
299 clone. */
300 else if (strncmp (symdata.name, expected, strlen (expected))
301 != 0)
303 fprintf (stderr,
304 ("test3: [%d]: unexpected syminfo name "
305 "got %s expected %s\n"),
306 j, symdata.name, expected);
307 symdata.failed = 1;
311 if (symdata.failed)
312 data.failed = 1;
316 printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
318 if (data.failed)
319 ++failures;
321 return failures;
324 int test5 (void) __attribute__ ((unused));
326 int global = 1;
329 test5 (void)
331 struct symdata symdata;
332 int i;
333 uintptr_t addr = (uintptr_t) &global;
335 if (sizeof (global) > 1)
336 addr += 1;
338 symdata.name = NULL;
339 symdata.val = 0;
340 symdata.size = 0;
341 symdata.failed = 0;
343 i = backtrace_syminfo (state, addr, callback_three,
344 error_callback_three, &symdata);
345 if (i == 0)
347 fprintf (stderr,
348 "test5: unexpected return value from backtrace_syminfo %d\n",
350 symdata.failed = 1;
353 if (!symdata.failed)
355 if (symdata.name == NULL)
357 fprintf (stderr, "test5: NULL syminfo name\n");
358 symdata.failed = 1;
360 else if (!(strncmp (symdata.name, "global", 6) == 0
361 && (symdata.name[6] == '\0'|| symdata.name[6] == '.')))
363 fprintf (stderr,
364 "test5: unexpected syminfo name got %s expected %s\n",
365 symdata.name, "global");
366 symdata.failed = 1;
368 else if (symdata.val != (uintptr_t) &global)
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;
376 else if (symdata.size != sizeof (global))
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;
386 printf ("%s: backtrace_syminfo variable\n",
387 symdata.failed ? "FAIL" : "PASS");
389 if (symdata.failed)
390 ++failures;
392 return failures;
396 main (int argc ATTRIBUTE_UNUSED, char **argv)
398 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
399 error_callback_create, NULL);
401 #if BACKTRACE_SUPPORTED
402 test1 ();
403 test3 ();
404 #if BACKTRACE_SUPPORTS_DATA
405 test5 ();
406 #endif
407 #endif
409 exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);