t_backtrace.c revision 276478
1254721Semaste/* $NetBSD: t_backtrace.c,v 1.16 2014/11/04 00:20:19 justin Exp $ */ 2254721Semaste 3254721Semaste/*- 4254721Semaste * Copyright (c) 2012 The NetBSD Foundation, Inc. 5254721Semaste * All rights reserved. 6254721Semaste * 7254721Semaste * This code is derived from software contributed to The NetBSD Foundation 8254721Semaste * by Christos Zoulas. 9254721Semaste * 10254721Semaste * Redistribution and use in source and binary forms, with or without 11254721Semaste * modification, are permitted provided that the following conditions 12254721Semaste * are met: 13254721Semaste * 1. Redistributions of source code must retain the above copyright 14254721Semaste * notice, this list of conditions and the following disclaimer. 15254721Semaste * 2. Redistributions in binary form must reproduce the above copyright 16254721Semaste * notice, this list of conditions and the following disclaimer in the 17254721Semaste * documentation and/or other materials provided with the distribution. 18254721Semaste * 19254721Semaste * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20254721Semaste * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21254721Semaste * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22254721Semaste * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23254721Semaste * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24254721Semaste * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25254721Semaste * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26254721Semaste * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27254721Semaste * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28254721Semaste * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29254721Semaste * POSSIBILITY OF SUCH DAMAGE. 30254721Semaste */ 31254721Semaste#include <sys/cdefs.h> 32254721Semaste__RCSID("$NetBSD: t_backtrace.c,v 1.16 2014/11/04 00:20:19 justin Exp $"); 33254721Semaste 34254721Semaste#include <atf-c.h> 35254721Semaste#include <string.h> 36254721Semaste#include <stdio.h> 37254721Semaste#include <stdlib.h> 38254721Semaste#include <execinfo.h> 39254721Semaste#include <unistd.h> 40254721Semaste 41254721Semaste#ifndef __arraycount 42254721Semaste#define __arraycount(a) (sizeof(a) / sizeof(a[0])) 43254721Semaste#endif 44254721Semaste 45254721Semastevoid myfunc3(size_t ncalls); 46254721Semastevoid myfunc2(size_t ncalls); 47254721Semastevoid myfunc1(size_t origcalls, volatile size_t ncalls); 48254721Semastevoid myfunc(size_t ncalls); 49254721Semaste 50254721Semastevolatile int prevent_inline; 51254721Semaste 52254721Semastevoid 53254721Semastemyfunc3(size_t ncalls) 54254721Semaste{ 55254721Semaste static const struct { 56254721Semaste const char *name; 57254721Semaste bool is_optional; 58254721Semaste } frames[] = { 59254721Semaste { "myfunc", false }, 60254721Semaste { "atfu_backtrace_fmt_basic_body", false }, 61254721Semaste { "atf_tc_run", false }, 62254721Semaste { "atf_tp_run", true }, 63254721Semaste { "run_tc", true }, 64254721Semaste { "controlled_main", true }, 65254721Semaste { "atf_tp_main", false }, 66254721Semaste { "main", true }, 67254721Semaste { "___start", true }, 68254721Semaste }; 69254721Semaste size_t j, nptrs, min_frames, max_frames; 70254721Semaste void *buffer[ncalls + 10]; 71254721Semaste char **strings; 72263367Semaste 73263367Semaste min_frames = 0; 74263367Semaste max_frames = 0; 75263367Semaste for (j = 0; j < __arraycount(frames); ++j) { 76263367Semaste if (!frames[j].is_optional) 77263367Semaste ++min_frames; 78263367Semaste ++max_frames; 79263367Semaste } 80263367Semaste nptrs = backtrace(buffer, __arraycount(buffer)); 81254721Semaste ATF_REQUIRE(nptrs != (size_t)-1); 82254721Semaste strings = backtrace_symbols_fmt(buffer, nptrs, "%n"); 83254721Semaste 84263367Semaste ATF_CHECK(strings != NULL); 85263367Semaste 86254721Semaste printf("got nptrs=%zu ncalls=%zu (min_frames: %zu, max_frames: %zu)\n", 87254721Semaste nptrs, ncalls, min_frames, max_frames); 88254721Semaste printf("backtrace is:\n"); 89254721Semaste for (j = 0; j < nptrs; j++) { 90254721Semaste printf("#%zu: %s\n", j, strings[j]); 91254721Semaste } 92254721Semaste 93254721Semaste ATF_REQUIRE(nptrs >= ncalls + 2 + min_frames); 94254721Semaste ATF_REQUIRE(nptrs <= ncalls + 2 + max_frames); 95254721Semaste ATF_CHECK_STREQ(strings[0], "myfunc3"); 96254721Semaste ATF_CHECK_STREQ(strings[1], "myfunc2"); 97254721Semaste 98254721Semaste for (j = 2; j < ncalls + 2; j++) 99254721Semaste ATF_CHECK_STREQ(strings[j], "myfunc1"); 100254721Semaste 101254721Semaste for (size_t i = 0; j < nptrs; i++, j++) { 102254721Semaste if (frames[i].is_optional && 103254721Semaste strcmp(strings[j], frames[i].name)) { 104254721Semaste --i; 105254721Semaste continue; 106254721Semaste } 107254721Semaste ATF_CHECK_STREQ(strings[j], frames[i].name); 108254721Semaste } 109254721Semaste 110254721Semaste free(strings); 111254721Semaste 112254721Semaste if (prevent_inline) 113254721Semaste vfork(); 114254721Semaste} 115254721Semaste 116254721Semastevoid 117254721Semastemyfunc2(size_t ncalls) 118254721Semaste{ 119254721Semaste myfunc3(ncalls); 120254721Semaste 121254721Semaste if (prevent_inline) 122254721Semaste vfork(); 123254721Semaste} 124254721Semaste 125254721Semastevoid 126254721Semastemyfunc1(size_t origcalls, volatile size_t ncalls) 127254721Semaste{ 128254721Semaste if (ncalls > 1) 129254721Semaste myfunc1(origcalls, ncalls - 1); 130254721Semaste else 131254721Semaste myfunc2(origcalls); 132254721Semaste 133254721Semaste if (prevent_inline) 134254721Semaste vfork(); 135254721Semaste} 136254721Semaste 137254721Semastevoid 138254721Semastemyfunc(size_t ncalls) 139254721Semaste{ 140254721Semaste myfunc1(ncalls, ncalls); 141254721Semaste 142254721Semaste if (prevent_inline) 143254721Semaste vfork(); 144254721Semaste} 145254721Semaste 146254721SemasteATF_TC(backtrace_fmt_basic); 147254721SemasteATF_TC_HEAD(backtrace_fmt_basic, tc) 148254721Semaste{ 149254721Semaste atf_tc_set_md_var(tc, "descr", "Test backtrace_fmt(3)"); 150254721Semaste atf_tc_set_md_var(tc, "require.files", "/proc/self"); 151254721Semaste} 152254721Semaste 153254721SemasteATF_TC_BODY(backtrace_fmt_basic, tc) 154254721Semaste{ 155254721Semaste myfunc(12); 156254721Semaste 157254721Semaste if (prevent_inline) 158254721Semaste vfork(); 159254721Semaste} 160254721Semaste 161254721SemasteATF_TP_ADD_TCS(tp) 162254721Semaste{ 163254721Semaste 164254721Semaste ATF_TP_ADD_TC(tp, backtrace_fmt_basic); 165254721Semaste 166254721Semaste return atf_no_error(); 167254721Semaste} 168254721Semaste