xref: /openbsd-src/regress/gnu/lib/libexecinfo/t_backtrace.c (revision 498c7b5e98c82ca5a0055f676f2a6e4214e2d9a8)
1*498c7b5eSderaadt /*	$OpenBSD: t_backtrace.c,v 1.2 2021/12/13 18:04:28 deraadt Exp $	*/
2bcc8c9abSjca 
3bcc8c9abSjca /*-
4bcc8c9abSjca  * Copyright (c) 2012 The NetBSD Foundation, Inc.
5bcc8c9abSjca  * All rights reserved.
6bcc8c9abSjca  *
7bcc8c9abSjca  * This code is derived from software contributed to The NetBSD Foundation
8bcc8c9abSjca  * by Christos Zoulas.
9bcc8c9abSjca  *
10bcc8c9abSjca  * Redistribution and use in source and binary forms, with or without
11bcc8c9abSjca  * modification, are permitted provided that the following conditions
12bcc8c9abSjca  * are met:
13bcc8c9abSjca  * 1. Redistributions of source code must retain the above copyright
14bcc8c9abSjca  *    notice, this list of conditions and the following disclaimer.
15bcc8c9abSjca  * 2. Redistributions in binary form must reproduce the above copyright
16bcc8c9abSjca  *    notice, this list of conditions and the following disclaimer in the
17bcc8c9abSjca  *    documentation and/or other materials provided with the distribution.
18bcc8c9abSjca  *
19bcc8c9abSjca  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20bcc8c9abSjca  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21bcc8c9abSjca  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22bcc8c9abSjca  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23bcc8c9abSjca  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24bcc8c9abSjca  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25bcc8c9abSjca  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26bcc8c9abSjca  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27bcc8c9abSjca  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28bcc8c9abSjca  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29bcc8c9abSjca  * POSSIBILITY OF SUCH DAMAGE.
30bcc8c9abSjca  */
31*498c7b5eSderaadt 
32*498c7b5eSderaadt #include <sys/types.h>
33bcc8c9abSjca 
34bcc8c9abSjca #include <atf-c.h>
35bcc8c9abSjca #include <string.h>
36bcc8c9abSjca #include <stdbool.h>
37bcc8c9abSjca #include <stdio.h>
38bcc8c9abSjca #include <stdlib.h>
39bcc8c9abSjca #include <execinfo.h>
40bcc8c9abSjca #include <unistd.h>
41bcc8c9abSjca 
42bcc8c9abSjca #ifndef __arraycount
43bcc8c9abSjca #define __arraycount(a) (sizeof(a) / sizeof(a[0]))
44bcc8c9abSjca #endif
45bcc8c9abSjca 
46bcc8c9abSjca void myfunc3(size_t ncalls);
47bcc8c9abSjca void myfunc2(size_t ncalls);
48bcc8c9abSjca void myfunc1(size_t origcalls, volatile size_t ncalls);
49bcc8c9abSjca void myfunc(size_t ncalls);
50bcc8c9abSjca 
51bcc8c9abSjca static volatile int prevent_inline;
52bcc8c9abSjca 
53bcc8c9abSjca void
myfunc3(size_t ncalls)54bcc8c9abSjca myfunc3(size_t ncalls)
55bcc8c9abSjca {
56bcc8c9abSjca 	static const struct {
57bcc8c9abSjca 		const char *name;
58bcc8c9abSjca 		bool is_optional;
59bcc8c9abSjca 	} frames[] = {
60bcc8c9abSjca 	    { "myfunc", false },
61bcc8c9abSjca 	    { "atf_body_backtrace_fmt_basic", false },
62bcc8c9abSjca 	    { "atf_test", true },
63bcc8c9abSjca 	    { "main", true },
64bcc8c9abSjca 	    { "_start", true },
65bcc8c9abSjca 	};
66bcc8c9abSjca 	size_t j, nptrs, min_frames, max_frames;
67bcc8c9abSjca 	void *buffer[ncalls + 10];
68bcc8c9abSjca 	char **strings;
69bcc8c9abSjca 
70bcc8c9abSjca 	min_frames = 0;
71bcc8c9abSjca 	max_frames = 0;
72bcc8c9abSjca 	for (j = 0; j < __arraycount(frames); ++j) {
73bcc8c9abSjca 		if (!frames[j].is_optional)
74bcc8c9abSjca 			++min_frames;
75bcc8c9abSjca 		++max_frames;
76bcc8c9abSjca 	}
77bcc8c9abSjca 	nptrs = backtrace(buffer, __arraycount(buffer));
78bcc8c9abSjca 	ATF_REQUIRE(nptrs != (size_t)-1);
79bcc8c9abSjca 	strings = backtrace_symbols_fmt(buffer, nptrs, "%n");
80bcc8c9abSjca 
81bcc8c9abSjca 	ATF_CHECK(strings != NULL);
82bcc8c9abSjca 
83bcc8c9abSjca 	printf("got nptrs=%zu ncalls=%zu (min_frames: %zu, max_frames: %zu)\n",
84bcc8c9abSjca 	    nptrs, ncalls, min_frames, max_frames);
85bcc8c9abSjca 	printf("backtrace is:\n");
86bcc8c9abSjca 	for (j = 0; j < nptrs; j++) {
87bcc8c9abSjca 		printf("#%zu: %s\n", j, strings[j]);
88bcc8c9abSjca 	}
89bcc8c9abSjca 
90bcc8c9abSjca 	ATF_REQUIRE(nptrs >= ncalls + 2 + min_frames);
91bcc8c9abSjca 	ATF_REQUIRE(nptrs <= ncalls + 2 + max_frames);
92bcc8c9abSjca 	ATF_CHECK_STREQ(strings[0], "myfunc3");
93bcc8c9abSjca 	ATF_CHECK_STREQ(strings[1], "myfunc2");
94bcc8c9abSjca 
95bcc8c9abSjca 	for (j = 2; j < ncalls + 2; j++)
96bcc8c9abSjca 		ATF_CHECK_STREQ(strings[j], "myfunc1");
97bcc8c9abSjca 
98bcc8c9abSjca 	for (size_t i = 0; j < nptrs; i++, j++) {
99bcc8c9abSjca 		if (frames[i].is_optional &&
100bcc8c9abSjca 		    strcmp(strings[j], frames[i].name)) {
101bcc8c9abSjca 			--i;
102bcc8c9abSjca 			continue;
103bcc8c9abSjca 		}
104bcc8c9abSjca 		ATF_CHECK_STREQ(strings[j], frames[i].name);
105bcc8c9abSjca 	}
106bcc8c9abSjca 
107bcc8c9abSjca 	free(strings);
108bcc8c9abSjca 
109bcc8c9abSjca 	if (prevent_inline)
110bcc8c9abSjca 		vfork();
111bcc8c9abSjca }
112bcc8c9abSjca 
113bcc8c9abSjca void
myfunc2(size_t ncalls)114bcc8c9abSjca myfunc2(size_t ncalls)
115bcc8c9abSjca {
116bcc8c9abSjca 	myfunc3(ncalls);
117bcc8c9abSjca 
118bcc8c9abSjca 	if (prevent_inline)
119bcc8c9abSjca 		vfork();
120bcc8c9abSjca }
121bcc8c9abSjca 
122bcc8c9abSjca void
myfunc1(size_t origcalls,volatile size_t ncalls)123bcc8c9abSjca myfunc1(size_t origcalls, volatile size_t ncalls)
124bcc8c9abSjca {
125bcc8c9abSjca 	if (ncalls > 1)
126bcc8c9abSjca 		myfunc1(origcalls, ncalls - 1);
127bcc8c9abSjca 	else
128bcc8c9abSjca 		myfunc2(origcalls);
129bcc8c9abSjca 
130bcc8c9abSjca 	if (prevent_inline)
131bcc8c9abSjca 		vfork();
132bcc8c9abSjca }
133bcc8c9abSjca 
134bcc8c9abSjca void
myfunc(size_t ncalls)135bcc8c9abSjca myfunc(size_t ncalls)
136bcc8c9abSjca {
137bcc8c9abSjca 	myfunc1(ncalls, ncalls);
138bcc8c9abSjca 
139bcc8c9abSjca 	if (prevent_inline)
140bcc8c9abSjca 		vfork();
141bcc8c9abSjca }
142bcc8c9abSjca 
143bcc8c9abSjca ATF_TC(backtrace_fmt_basic);
ATF_TC_HEAD(backtrace_fmt_basic,tc)144bcc8c9abSjca ATF_TC_HEAD(backtrace_fmt_basic, tc)
145bcc8c9abSjca {
146bcc8c9abSjca 	atf_tc_set_md_var(tc, "descr", "Test backtrace_fmt(3)");
147bcc8c9abSjca 	atf_tc_set_md_var(tc, "require.files", "/proc/self");
148bcc8c9abSjca }
149bcc8c9abSjca 
ATF_TC_BODY(backtrace_fmt_basic,tc)150bcc8c9abSjca ATF_TC_BODY(backtrace_fmt_basic, tc)
151bcc8c9abSjca {
152bcc8c9abSjca 	myfunc(12);
153bcc8c9abSjca 
154bcc8c9abSjca 	if (prevent_inline)
155bcc8c9abSjca 		vfork();
156bcc8c9abSjca }
157bcc8c9abSjca 
ATF_TP_ADD_TCS(tp)158bcc8c9abSjca ATF_TP_ADD_TCS(tp)
159bcc8c9abSjca {
160bcc8c9abSjca 
161bcc8c9abSjca 	ATF_TP_ADD_TC(tp, backtrace_fmt_basic);
162bcc8c9abSjca 
163bcc8c9abSjca 	return atf_no_error();
164bcc8c9abSjca }
165