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