1*0a6a1f1dSLionel Sambuc /* $NetBSD: t_backtrace.c,v 1.16 2014/11/04 00:20:19 justin Exp $ */
211be35a1SLionel Sambuc
311be35a1SLionel Sambuc /*-
411be35a1SLionel Sambuc * Copyright (c) 2012 The NetBSD Foundation, Inc.
511be35a1SLionel Sambuc * All rights reserved.
611be35a1SLionel Sambuc *
711be35a1SLionel Sambuc * This code is derived from software contributed to The NetBSD Foundation
811be35a1SLionel Sambuc * by Christos Zoulas.
911be35a1SLionel Sambuc *
1011be35a1SLionel Sambuc * Redistribution and use in source and binary forms, with or without
1111be35a1SLionel Sambuc * modification, are permitted provided that the following conditions
1211be35a1SLionel Sambuc * are met:
1311be35a1SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
1411be35a1SLionel Sambuc * notice, this list of conditions and the following disclaimer.
1511be35a1SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
1611be35a1SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
1711be35a1SLionel Sambuc * documentation and/or other materials provided with the distribution.
1811be35a1SLionel Sambuc *
1911be35a1SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2011be35a1SLionel Sambuc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2111be35a1SLionel Sambuc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2211be35a1SLionel Sambuc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2311be35a1SLionel Sambuc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2411be35a1SLionel Sambuc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2511be35a1SLionel Sambuc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2611be35a1SLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2711be35a1SLionel Sambuc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2811be35a1SLionel Sambuc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2911be35a1SLionel Sambuc * POSSIBILITY OF SUCH DAMAGE.
3011be35a1SLionel Sambuc */
3111be35a1SLionel Sambuc #include <sys/cdefs.h>
32*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: t_backtrace.c,v 1.16 2014/11/04 00:20:19 justin Exp $");
3311be35a1SLionel Sambuc
3411be35a1SLionel Sambuc #include <atf-c.h>
3511be35a1SLionel Sambuc #include <string.h>
36*0a6a1f1dSLionel Sambuc #include <stdio.h>
3711be35a1SLionel Sambuc #include <stdlib.h>
3811be35a1SLionel Sambuc #include <execinfo.h>
3911be35a1SLionel Sambuc #include <unistd.h>
4011be35a1SLionel Sambuc
4111be35a1SLionel Sambuc #ifndef __arraycount
4211be35a1SLionel Sambuc #define __arraycount(a) (sizeof(a) / sizeof(a[0]))
4311be35a1SLionel Sambuc #endif
4411be35a1SLionel Sambuc
4584d9c625SLionel Sambuc void myfunc3(size_t ncalls);
4684d9c625SLionel Sambuc void myfunc2(size_t ncalls);
4784d9c625SLionel Sambuc void myfunc1(size_t origcalls, volatile size_t ncalls);
4884d9c625SLionel Sambuc void myfunc(size_t ncalls);
4984d9c625SLionel Sambuc
5011be35a1SLionel Sambuc volatile int prevent_inline;
5111be35a1SLionel Sambuc
5284d9c625SLionel Sambuc void
myfunc3(size_t ncalls)5311be35a1SLionel Sambuc myfunc3(size_t ncalls)
5411be35a1SLionel Sambuc {
55*0a6a1f1dSLionel Sambuc static const struct {
56*0a6a1f1dSLionel Sambuc const char *name;
57*0a6a1f1dSLionel Sambuc bool is_optional;
58*0a6a1f1dSLionel Sambuc } frames[] = {
59*0a6a1f1dSLionel Sambuc { "myfunc", false },
60*0a6a1f1dSLionel Sambuc { "atfu_backtrace_fmt_basic_body", false },
61*0a6a1f1dSLionel Sambuc { "atf_tc_run", false },
62*0a6a1f1dSLionel Sambuc { "atf_tp_run", true },
63*0a6a1f1dSLionel Sambuc { "run_tc", true },
64*0a6a1f1dSLionel Sambuc { "controlled_main", true },
65*0a6a1f1dSLionel Sambuc { "atf_tp_main", false },
66*0a6a1f1dSLionel Sambuc { "main", true },
67*0a6a1f1dSLionel Sambuc { "___start", true },
68*0a6a1f1dSLionel Sambuc };
6911be35a1SLionel Sambuc size_t j, nptrs, min_frames, max_frames;
7011be35a1SLionel Sambuc void *buffer[ncalls + 10];
7111be35a1SLionel Sambuc char **strings;
7211be35a1SLionel Sambuc
7311be35a1SLionel Sambuc min_frames = 0;
7411be35a1SLionel Sambuc max_frames = 0;
75*0a6a1f1dSLionel Sambuc for (j = 0; j < __arraycount(frames); ++j) {
76*0a6a1f1dSLionel Sambuc if (!frames[j].is_optional)
7711be35a1SLionel Sambuc ++min_frames;
7811be35a1SLionel Sambuc ++max_frames;
7911be35a1SLionel Sambuc }
8011be35a1SLionel Sambuc nptrs = backtrace(buffer, __arraycount(buffer));
81*0a6a1f1dSLionel Sambuc ATF_REQUIRE(nptrs != (size_t)-1);
8211be35a1SLionel Sambuc strings = backtrace_symbols_fmt(buffer, nptrs, "%n");
8311be35a1SLionel Sambuc
8411be35a1SLionel Sambuc ATF_CHECK(strings != NULL);
85*0a6a1f1dSLionel Sambuc
86*0a6a1f1dSLionel Sambuc printf("got nptrs=%zu ncalls=%zu (min_frames: %zu, max_frames: %zu)\n",
87*0a6a1f1dSLionel Sambuc nptrs, ncalls, min_frames, max_frames);
88*0a6a1f1dSLionel Sambuc printf("backtrace is:\n");
89*0a6a1f1dSLionel Sambuc for (j = 0; j < nptrs; j++) {
90*0a6a1f1dSLionel Sambuc printf("#%zu: %s\n", j, strings[j]);
91*0a6a1f1dSLionel Sambuc }
92*0a6a1f1dSLionel Sambuc
93*0a6a1f1dSLionel Sambuc ATF_REQUIRE(nptrs >= ncalls + 2 + min_frames);
94*0a6a1f1dSLionel Sambuc ATF_REQUIRE(nptrs <= ncalls + 2 + max_frames);
9511be35a1SLionel Sambuc ATF_CHECK_STREQ(strings[0], "myfunc3");
9611be35a1SLionel Sambuc ATF_CHECK_STREQ(strings[1], "myfunc2");
9711be35a1SLionel Sambuc
9811be35a1SLionel Sambuc for (j = 2; j < ncalls + 2; j++)
9911be35a1SLionel Sambuc ATF_CHECK_STREQ(strings[j], "myfunc1");
10011be35a1SLionel Sambuc
10111be35a1SLionel Sambuc for (size_t i = 0; j < nptrs; i++, j++) {
102*0a6a1f1dSLionel Sambuc if (frames[i].is_optional &&
103*0a6a1f1dSLionel Sambuc strcmp(strings[j], frames[i].name)) {
10411be35a1SLionel Sambuc --i;
10511be35a1SLionel Sambuc continue;
10611be35a1SLionel Sambuc }
107*0a6a1f1dSLionel Sambuc ATF_CHECK_STREQ(strings[j], frames[i].name);
10811be35a1SLionel Sambuc }
10911be35a1SLionel Sambuc
11011be35a1SLionel Sambuc free(strings);
11111be35a1SLionel Sambuc
11211be35a1SLionel Sambuc if (prevent_inline)
11311be35a1SLionel Sambuc vfork();
11411be35a1SLionel Sambuc }
11511be35a1SLionel Sambuc
11684d9c625SLionel Sambuc void
myfunc2(size_t ncalls)11711be35a1SLionel Sambuc myfunc2(size_t ncalls)
11811be35a1SLionel Sambuc {
11911be35a1SLionel Sambuc myfunc3(ncalls);
12011be35a1SLionel Sambuc
12111be35a1SLionel Sambuc if (prevent_inline)
12211be35a1SLionel Sambuc vfork();
12311be35a1SLionel Sambuc }
12411be35a1SLionel Sambuc
12584d9c625SLionel Sambuc void
myfunc1(size_t origcalls,volatile size_t ncalls)12611be35a1SLionel Sambuc myfunc1(size_t origcalls, volatile size_t ncalls)
12711be35a1SLionel Sambuc {
12811be35a1SLionel Sambuc if (ncalls > 1)
12911be35a1SLionel Sambuc myfunc1(origcalls, ncalls - 1);
13011be35a1SLionel Sambuc else
13111be35a1SLionel Sambuc myfunc2(origcalls);
13211be35a1SLionel Sambuc
13311be35a1SLionel Sambuc if (prevent_inline)
13411be35a1SLionel Sambuc vfork();
13511be35a1SLionel Sambuc }
13611be35a1SLionel Sambuc
13784d9c625SLionel Sambuc void
myfunc(size_t ncalls)13811be35a1SLionel Sambuc myfunc(size_t ncalls)
13911be35a1SLionel Sambuc {
14011be35a1SLionel Sambuc myfunc1(ncalls, ncalls);
14111be35a1SLionel Sambuc
14211be35a1SLionel Sambuc if (prevent_inline)
14311be35a1SLionel Sambuc vfork();
14411be35a1SLionel Sambuc }
14511be35a1SLionel Sambuc
14611be35a1SLionel Sambuc ATF_TC(backtrace_fmt_basic);
ATF_TC_HEAD(backtrace_fmt_basic,tc)14711be35a1SLionel Sambuc ATF_TC_HEAD(backtrace_fmt_basic, tc)
14811be35a1SLionel Sambuc {
14911be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "Test backtrace_fmt(3)");
150*0a6a1f1dSLionel Sambuc atf_tc_set_md_var(tc, "require.files", "/proc/self");
15111be35a1SLionel Sambuc }
15211be35a1SLionel Sambuc
ATF_TC_BODY(backtrace_fmt_basic,tc)15311be35a1SLionel Sambuc ATF_TC_BODY(backtrace_fmt_basic, tc)
15411be35a1SLionel Sambuc {
15511be35a1SLionel Sambuc myfunc(12);
15684d9c625SLionel Sambuc
15784d9c625SLionel Sambuc if (prevent_inline)
15884d9c625SLionel Sambuc vfork();
15911be35a1SLionel Sambuc }
16011be35a1SLionel Sambuc
ATF_TP_ADD_TCS(tp)16111be35a1SLionel Sambuc ATF_TP_ADD_TCS(tp)
16211be35a1SLionel Sambuc {
16311be35a1SLionel Sambuc
16411be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, backtrace_fmt_basic);
16511be35a1SLionel Sambuc
16611be35a1SLionel Sambuc return atf_no_error();
16711be35a1SLionel Sambuc }
168