1*b0d29bc4SBrooks Davis // Copyright 2012 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis // documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis // may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis // without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis
29*b0d29bc4SBrooks Davis #include "utils/stacktrace.hpp"
30*b0d29bc4SBrooks Davis
31*b0d29bc4SBrooks Davis extern "C" {
32*b0d29bc4SBrooks Davis #include <sys/resource.h>
33*b0d29bc4SBrooks Davis #include <sys/types.h>
34*b0d29bc4SBrooks Davis #include <sys/stat.h>
35*b0d29bc4SBrooks Davis
36*b0d29bc4SBrooks Davis #include <signal.h>
37*b0d29bc4SBrooks Davis #include <unistd.h>
38*b0d29bc4SBrooks Davis }
39*b0d29bc4SBrooks Davis
40*b0d29bc4SBrooks Davis #include <iostream>
41*b0d29bc4SBrooks Davis #include <sstream>
42*b0d29bc4SBrooks Davis
43*b0d29bc4SBrooks Davis #include <atf-c++.hpp>
44*b0d29bc4SBrooks Davis
45*b0d29bc4SBrooks Davis #include "utils/datetime.hpp"
46*b0d29bc4SBrooks Davis #include "utils/env.hpp"
47*b0d29bc4SBrooks Davis #include "utils/fs/operations.hpp"
48*b0d29bc4SBrooks Davis #include "utils/fs/path.hpp"
49*b0d29bc4SBrooks Davis #include "utils/optional.ipp"
50*b0d29bc4SBrooks Davis #include "utils/process/executor.ipp"
51*b0d29bc4SBrooks Davis #include "utils/process/child.ipp"
52*b0d29bc4SBrooks Davis #include "utils/process/operations.hpp"
53*b0d29bc4SBrooks Davis #include "utils/process/status.hpp"
54*b0d29bc4SBrooks Davis #include "utils/sanity.hpp"
55*b0d29bc4SBrooks Davis #include "utils/test_utils.ipp"
56*b0d29bc4SBrooks Davis
57*b0d29bc4SBrooks Davis namespace datetime = utils::datetime;
58*b0d29bc4SBrooks Davis namespace executor = utils::process::executor;
59*b0d29bc4SBrooks Davis namespace fs = utils::fs;
60*b0d29bc4SBrooks Davis namespace process = utils::process;
61*b0d29bc4SBrooks Davis
62*b0d29bc4SBrooks Davis using utils::none;
63*b0d29bc4SBrooks Davis using utils::optional;
64*b0d29bc4SBrooks Davis
65*b0d29bc4SBrooks Davis
66*b0d29bc4SBrooks Davis namespace {
67*b0d29bc4SBrooks Davis
68*b0d29bc4SBrooks Davis
69*b0d29bc4SBrooks Davis /// Functor to execute a binary in a subprocess.
70*b0d29bc4SBrooks Davis ///
71*b0d29bc4SBrooks Davis /// The provided binary is copied to the current work directory before being
72*b0d29bc4SBrooks Davis /// executed and the copy is given the name chosen by the user. The copy is
73*b0d29bc4SBrooks Davis /// necessary so that we have a deterministic location for where core files may
74*b0d29bc4SBrooks Davis /// be dumped (if they happen to be dumped in the current directory).
75*b0d29bc4SBrooks Davis class crash_me {
76*b0d29bc4SBrooks Davis /// Path to the binary to execute.
77*b0d29bc4SBrooks Davis const fs::path _binary;
78*b0d29bc4SBrooks Davis
79*b0d29bc4SBrooks Davis /// Name of the binary after being copied.
80*b0d29bc4SBrooks Davis const fs::path _copy_name;
81*b0d29bc4SBrooks Davis
82*b0d29bc4SBrooks Davis public:
83*b0d29bc4SBrooks Davis /// Constructor.
84*b0d29bc4SBrooks Davis ///
85*b0d29bc4SBrooks Davis /// \param binary_ Path to binary to execute.
86*b0d29bc4SBrooks Davis /// \param copy_name_ Name of the binary after being copied. If empty,
87*b0d29bc4SBrooks Davis /// use the leaf name of binary_.
crash_me(const fs::path & binary_,const std::string & copy_name_="")88*b0d29bc4SBrooks Davis explicit crash_me(const fs::path& binary_,
89*b0d29bc4SBrooks Davis const std::string& copy_name_ = "") :
90*b0d29bc4SBrooks Davis _binary(binary_),
91*b0d29bc4SBrooks Davis _copy_name(copy_name_.empty() ? binary_.leaf_name() : copy_name_)
92*b0d29bc4SBrooks Davis {
93*b0d29bc4SBrooks Davis }
94*b0d29bc4SBrooks Davis
95*b0d29bc4SBrooks Davis /// Runs the binary.
96*b0d29bc4SBrooks Davis void
operator ()(void) const97*b0d29bc4SBrooks Davis operator()(void) const UTILS_NORETURN
98*b0d29bc4SBrooks Davis {
99*b0d29bc4SBrooks Davis atf::utils::copy_file(_binary.str(), _copy_name.str());
100*b0d29bc4SBrooks Davis
101*b0d29bc4SBrooks Davis const std::vector< std::string > args;
102*b0d29bc4SBrooks Davis process::exec(_copy_name, args);
103*b0d29bc4SBrooks Davis }
104*b0d29bc4SBrooks Davis
105*b0d29bc4SBrooks Davis /// Runs the binary.
106*b0d29bc4SBrooks Davis ///
107*b0d29bc4SBrooks Davis /// This interface is exposed to support passing crash_me to the executor.
108*b0d29bc4SBrooks Davis void
operator ()(const fs::path &) const109*b0d29bc4SBrooks Davis operator()(const fs::path& /* control_directory */) const
110*b0d29bc4SBrooks Davis UTILS_NORETURN
111*b0d29bc4SBrooks Davis {
112*b0d29bc4SBrooks Davis (*this)(); // Delegate to ensure the two entry points remain in sync.
113*b0d29bc4SBrooks Davis }
114*b0d29bc4SBrooks Davis };
115*b0d29bc4SBrooks Davis
116*b0d29bc4SBrooks Davis
117*b0d29bc4SBrooks Davis static void child_exit(const fs::path&) UTILS_NORETURN;
118*b0d29bc4SBrooks Davis
119*b0d29bc4SBrooks Davis
120*b0d29bc4SBrooks Davis /// Subprocess that exits cleanly.
121*b0d29bc4SBrooks Davis static void
child_exit(const fs::path &)122*b0d29bc4SBrooks Davis child_exit(const fs::path& /* control_directory */)
123*b0d29bc4SBrooks Davis {
124*b0d29bc4SBrooks Davis ::_exit(EXIT_SUCCESS);
125*b0d29bc4SBrooks Davis }
126*b0d29bc4SBrooks Davis
127*b0d29bc4SBrooks Davis
128*b0d29bc4SBrooks Davis static void child_pause(const fs::path&) UTILS_NORETURN;
129*b0d29bc4SBrooks Davis
130*b0d29bc4SBrooks Davis
131*b0d29bc4SBrooks Davis /// Subprocess that just blocks.
132*b0d29bc4SBrooks Davis static void
child_pause(const fs::path &)133*b0d29bc4SBrooks Davis child_pause(const fs::path& /* control_directory */)
134*b0d29bc4SBrooks Davis {
135*b0d29bc4SBrooks Davis sigset_t mask;
136*b0d29bc4SBrooks Davis sigemptyset(&mask);
137*b0d29bc4SBrooks Davis for (;;) {
138*b0d29bc4SBrooks Davis ::sigsuspend(&mask);
139*b0d29bc4SBrooks Davis }
140*b0d29bc4SBrooks Davis std::abort();
141*b0d29bc4SBrooks Davis }
142*b0d29bc4SBrooks Davis
143*b0d29bc4SBrooks Davis
144*b0d29bc4SBrooks Davis /// Generates a core dump, if possible.
145*b0d29bc4SBrooks Davis ///
146*b0d29bc4SBrooks Davis /// \post If this fails to generate a core file, the test case is marked as
147*b0d29bc4SBrooks Davis /// skipped. The caller can rely on this when attempting further checks on the
148*b0d29bc4SBrooks Davis /// core dump by assuming that the core dump exists somewhere.
149*b0d29bc4SBrooks Davis ///
150*b0d29bc4SBrooks Davis /// \param test_case Pointer to the caller test case, needed to obtain the path
151*b0d29bc4SBrooks Davis /// to the source directory.
152*b0d29bc4SBrooks Davis /// \param base_name Name of the binary to execute, which will be a copy of a
153*b0d29bc4SBrooks Davis /// helper binary that always crashes. This name should later be part of
154*b0d29bc4SBrooks Davis /// the core filename.
155*b0d29bc4SBrooks Davis ///
156*b0d29bc4SBrooks Davis /// \return The status of the crashed binary.
157*b0d29bc4SBrooks Davis static process::status
generate_core(const atf::tests::tc * test_case,const char * base_name)158*b0d29bc4SBrooks Davis generate_core(const atf::tests::tc* test_case, const char* base_name)
159*b0d29bc4SBrooks Davis {
160*b0d29bc4SBrooks Davis utils::prepare_coredump_test(test_case);
161*b0d29bc4SBrooks Davis
162*b0d29bc4SBrooks Davis const fs::path helper = fs::path(test_case->get_config_var("srcdir")) /
163*b0d29bc4SBrooks Davis "stacktrace_helper";
164*b0d29bc4SBrooks Davis
165*b0d29bc4SBrooks Davis const process::status status = process::child::fork_files(
166*b0d29bc4SBrooks Davis crash_me(helper, base_name),
167*b0d29bc4SBrooks Davis fs::path("unused.out"), fs::path("unused.err"))->wait();
168*b0d29bc4SBrooks Davis ATF_REQUIRE(status.signaled());
169*b0d29bc4SBrooks Davis if (!status.coredump())
170*b0d29bc4SBrooks Davis ATF_SKIP("Test failed to generate core dump");
171*b0d29bc4SBrooks Davis return status;
172*b0d29bc4SBrooks Davis }
173*b0d29bc4SBrooks Davis
174*b0d29bc4SBrooks Davis
175*b0d29bc4SBrooks Davis /// Generates a core dump, if possible.
176*b0d29bc4SBrooks Davis ///
177*b0d29bc4SBrooks Davis /// \post If this fails to generate a core file, the test case is marked as
178*b0d29bc4SBrooks Davis /// skipped. The caller can rely on this when attempting further checks on the
179*b0d29bc4SBrooks Davis /// core dump by assuming that the core dump exists somewhere.
180*b0d29bc4SBrooks Davis ///
181*b0d29bc4SBrooks Davis /// \param test_case Pointer to the caller test case, needed to obtain the path
182*b0d29bc4SBrooks Davis /// to the source directory.
183*b0d29bc4SBrooks Davis /// \param base_name Name of the binary to execute, which will be a copy of a
184*b0d29bc4SBrooks Davis /// helper binary that always crashes. This name should later be part of
185*b0d29bc4SBrooks Davis /// the core filename.
186*b0d29bc4SBrooks Davis /// \param executor_handle Executor to use to generate the core dump.
187*b0d29bc4SBrooks Davis ///
188*b0d29bc4SBrooks Davis /// \return The exit handle of the subprocess so that a stacktrace can be
189*b0d29bc4SBrooks Davis /// executed reusing this context later on.
190*b0d29bc4SBrooks Davis static executor::exit_handle
generate_core(const atf::tests::tc * test_case,const char * base_name,executor::executor_handle & executor_handle)191*b0d29bc4SBrooks Davis generate_core(const atf::tests::tc* test_case, const char* base_name,
192*b0d29bc4SBrooks Davis executor::executor_handle& executor_handle)
193*b0d29bc4SBrooks Davis {
194*b0d29bc4SBrooks Davis utils::prepare_coredump_test(test_case);
195*b0d29bc4SBrooks Davis
196*b0d29bc4SBrooks Davis const fs::path helper = fs::path(test_case->get_config_var("srcdir")) /
197*b0d29bc4SBrooks Davis "stacktrace_helper";
198*b0d29bc4SBrooks Davis
199*b0d29bc4SBrooks Davis const executor::exec_handle exec_handle = executor_handle.spawn(
200*b0d29bc4SBrooks Davis crash_me(helper, base_name), datetime::delta(60, 0), none, none, none);
201*b0d29bc4SBrooks Davis const executor::exit_handle exit_handle = executor_handle.wait(exec_handle);
202*b0d29bc4SBrooks Davis
203*b0d29bc4SBrooks Davis if (!exit_handle.status())
204*b0d29bc4SBrooks Davis ATF_SKIP("Test failed to generate core dump (timed out)");
205*b0d29bc4SBrooks Davis const process::status& status = exit_handle.status().get();
206*b0d29bc4SBrooks Davis ATF_REQUIRE(status.signaled());
207*b0d29bc4SBrooks Davis if (!status.coredump())
208*b0d29bc4SBrooks Davis ATF_SKIP("Test failed to generate core dump");
209*b0d29bc4SBrooks Davis
210*b0d29bc4SBrooks Davis return exit_handle;
211*b0d29bc4SBrooks Davis }
212*b0d29bc4SBrooks Davis
213*b0d29bc4SBrooks Davis
214*b0d29bc4SBrooks Davis /// Creates a script.
215*b0d29bc4SBrooks Davis ///
216*b0d29bc4SBrooks Davis /// \param script Path to the script to create.
217*b0d29bc4SBrooks Davis /// \param contents Contents of the script.
218*b0d29bc4SBrooks Davis static void
create_script(const char * script,const std::string & contents)219*b0d29bc4SBrooks Davis create_script(const char* script, const std::string& contents)
220*b0d29bc4SBrooks Davis {
221*b0d29bc4SBrooks Davis atf::utils::create_file(script, "#! /bin/sh\n\n" + contents);
222*b0d29bc4SBrooks Davis ATF_REQUIRE(::chmod(script, 0755) != -1);
223*b0d29bc4SBrooks Davis }
224*b0d29bc4SBrooks Davis
225*b0d29bc4SBrooks Davis
226*b0d29bc4SBrooks Davis } // anonymous namespace
227*b0d29bc4SBrooks Davis
228*b0d29bc4SBrooks Davis
229*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(unlimit_core_size);
ATF_TEST_CASE_BODY(unlimit_core_size)230*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(unlimit_core_size)
231*b0d29bc4SBrooks Davis {
232*b0d29bc4SBrooks Davis utils::require_run_coredump_tests(this);
233*b0d29bc4SBrooks Davis
234*b0d29bc4SBrooks Davis struct rlimit rl;
235*b0d29bc4SBrooks Davis rl.rlim_cur = 0;
236*b0d29bc4SBrooks Davis rl.rlim_max = RLIM_INFINITY;
237*b0d29bc4SBrooks Davis if (::setrlimit(RLIMIT_CORE, &rl) == -1)
238*b0d29bc4SBrooks Davis skip("Failed to lower the core size limit");
239*b0d29bc4SBrooks Davis
240*b0d29bc4SBrooks Davis ATF_REQUIRE(utils::unlimit_core_size());
241*b0d29bc4SBrooks Davis
242*b0d29bc4SBrooks Davis const fs::path helper = fs::path(get_config_var("srcdir")) /
243*b0d29bc4SBrooks Davis "stacktrace_helper";
244*b0d29bc4SBrooks Davis const process::status status = process::child::fork_files(
245*b0d29bc4SBrooks Davis crash_me(helper),
246*b0d29bc4SBrooks Davis fs::path("unused.out"), fs::path("unused.err"))->wait();
247*b0d29bc4SBrooks Davis ATF_REQUIRE(status.signaled());
248*b0d29bc4SBrooks Davis if (!status.coredump())
249*b0d29bc4SBrooks Davis fail("Core not dumped as expected");
250*b0d29bc4SBrooks Davis }
251*b0d29bc4SBrooks Davis
252*b0d29bc4SBrooks Davis
253*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(unlimit_core_size__hard_is_zero);
ATF_TEST_CASE_BODY(unlimit_core_size__hard_is_zero)254*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(unlimit_core_size__hard_is_zero)
255*b0d29bc4SBrooks Davis {
256*b0d29bc4SBrooks Davis utils::require_run_coredump_tests(this);
257*b0d29bc4SBrooks Davis
258*b0d29bc4SBrooks Davis struct rlimit rl;
259*b0d29bc4SBrooks Davis rl.rlim_cur = 0;
260*b0d29bc4SBrooks Davis rl.rlim_max = 0;
261*b0d29bc4SBrooks Davis if (::setrlimit(RLIMIT_CORE, &rl) == -1)
262*b0d29bc4SBrooks Davis skip("Failed to lower the core size limit");
263*b0d29bc4SBrooks Davis
264*b0d29bc4SBrooks Davis ATF_REQUIRE(!utils::unlimit_core_size());
265*b0d29bc4SBrooks Davis
266*b0d29bc4SBrooks Davis const fs::path helper = fs::path(get_config_var("srcdir")) /
267*b0d29bc4SBrooks Davis "stacktrace_helper";
268*b0d29bc4SBrooks Davis const process::status status = process::child::fork_files(
269*b0d29bc4SBrooks Davis crash_me(helper),
270*b0d29bc4SBrooks Davis fs::path("unused.out"), fs::path("unused.err"))->wait();
271*b0d29bc4SBrooks Davis ATF_REQUIRE(status.signaled());
272*b0d29bc4SBrooks Davis ATF_REQUIRE(!status.coredump());
273*b0d29bc4SBrooks Davis }
274*b0d29bc4SBrooks Davis
275*b0d29bc4SBrooks Davis
276*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(find_gdb__use_builtin);
ATF_TEST_CASE_BODY(find_gdb__use_builtin)277*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(find_gdb__use_builtin)
278*b0d29bc4SBrooks Davis {
279*b0d29bc4SBrooks Davis utils::builtin_gdb = "/path/to/gdb";
280*b0d29bc4SBrooks Davis optional< fs::path > gdb = utils::find_gdb();
281*b0d29bc4SBrooks Davis ATF_REQUIRE(gdb);
282*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ("/path/to/gdb", gdb.get().str());
283*b0d29bc4SBrooks Davis }
284*b0d29bc4SBrooks Davis
285*b0d29bc4SBrooks Davis
286*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(find_gdb__search_builtin__ok);
ATF_TEST_CASE_BODY(find_gdb__search_builtin__ok)287*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(find_gdb__search_builtin__ok)
288*b0d29bc4SBrooks Davis {
289*b0d29bc4SBrooks Davis atf::utils::create_file("custom-name", "");
290*b0d29bc4SBrooks Davis ATF_REQUIRE(::chmod("custom-name", 0755) != -1);
291*b0d29bc4SBrooks Davis const fs::path exp_gdb = fs::path("custom-name").to_absolute();
292*b0d29bc4SBrooks Davis
293*b0d29bc4SBrooks Davis utils::setenv("PATH", "/non-existent/location:.:/bin");
294*b0d29bc4SBrooks Davis
295*b0d29bc4SBrooks Davis utils::builtin_gdb = "custom-name";
296*b0d29bc4SBrooks Davis optional< fs::path > gdb = utils::find_gdb();
297*b0d29bc4SBrooks Davis ATF_REQUIRE(gdb);
298*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(exp_gdb, gdb.get());
299*b0d29bc4SBrooks Davis }
300*b0d29bc4SBrooks Davis
301*b0d29bc4SBrooks Davis
302*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(find_gdb__search_builtin__fail);
ATF_TEST_CASE_BODY(find_gdb__search_builtin__fail)303*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(find_gdb__search_builtin__fail)
304*b0d29bc4SBrooks Davis {
305*b0d29bc4SBrooks Davis utils::setenv("PATH", ".");
306*b0d29bc4SBrooks Davis utils::builtin_gdb = "foo";
307*b0d29bc4SBrooks Davis optional< fs::path > gdb = utils::find_gdb();
308*b0d29bc4SBrooks Davis ATF_REQUIRE(!gdb);
309*b0d29bc4SBrooks Davis }
310*b0d29bc4SBrooks Davis
311*b0d29bc4SBrooks Davis
312*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(find_gdb__bogus_value);
ATF_TEST_CASE_BODY(find_gdb__bogus_value)313*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(find_gdb__bogus_value)
314*b0d29bc4SBrooks Davis {
315*b0d29bc4SBrooks Davis utils::builtin_gdb = "";
316*b0d29bc4SBrooks Davis optional< fs::path > gdb = utils::find_gdb();
317*b0d29bc4SBrooks Davis ATF_REQUIRE(!gdb);
318*b0d29bc4SBrooks Davis }
319*b0d29bc4SBrooks Davis
320*b0d29bc4SBrooks Davis
321*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(find_core__found__short);
ATF_TEST_CASE_BODY(find_core__found__short)322*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(find_core__found__short)
323*b0d29bc4SBrooks Davis {
324*b0d29bc4SBrooks Davis const process::status status = generate_core(this, "short");
325*b0d29bc4SBrooks Davis INV(status.coredump());
326*b0d29bc4SBrooks Davis const optional< fs::path > core_name = utils::find_core(
327*b0d29bc4SBrooks Davis fs::path("short"), status, fs::path("."));
328*b0d29bc4SBrooks Davis if (!core_name)
329*b0d29bc4SBrooks Davis fail("Core dumped, but no candidates found");
330*b0d29bc4SBrooks Davis ATF_REQUIRE(core_name.get().str().find("core") != std::string::npos);
331*b0d29bc4SBrooks Davis ATF_REQUIRE(fs::exists(core_name.get()));
332*b0d29bc4SBrooks Davis }
333*b0d29bc4SBrooks Davis
334*b0d29bc4SBrooks Davis
335*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(find_core__found__long);
ATF_TEST_CASE_BODY(find_core__found__long)336*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(find_core__found__long)
337*b0d29bc4SBrooks Davis {
338*b0d29bc4SBrooks Davis const process::status status = generate_core(
339*b0d29bc4SBrooks Davis this, "long-name-that-may-be-truncated-in-some-systems");
340*b0d29bc4SBrooks Davis INV(status.coredump());
341*b0d29bc4SBrooks Davis const optional< fs::path > core_name = utils::find_core(
342*b0d29bc4SBrooks Davis fs::path("long-name-that-may-be-truncated-in-some-systems"),
343*b0d29bc4SBrooks Davis status, fs::path("."));
344*b0d29bc4SBrooks Davis if (!core_name)
345*b0d29bc4SBrooks Davis fail("Core dumped, but no candidates found");
346*b0d29bc4SBrooks Davis ATF_REQUIRE(core_name.get().str().find("core") != std::string::npos);
347*b0d29bc4SBrooks Davis ATF_REQUIRE(fs::exists(core_name.get()));
348*b0d29bc4SBrooks Davis }
349*b0d29bc4SBrooks Davis
350*b0d29bc4SBrooks Davis
351*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(find_core__not_found);
ATF_TEST_CASE_BODY(find_core__not_found)352*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(find_core__not_found)
353*b0d29bc4SBrooks Davis {
354*b0d29bc4SBrooks Davis const process::status status = process::status::fake_signaled(SIGILL, true);
355*b0d29bc4SBrooks Davis const optional< fs::path > core_name = utils::find_core(
356*b0d29bc4SBrooks Davis fs::path("missing"), status, fs::path("."));
357*b0d29bc4SBrooks Davis if (core_name)
358*b0d29bc4SBrooks Davis fail("Core not dumped, but candidate found: " + core_name.get().str());
359*b0d29bc4SBrooks Davis }
360*b0d29bc4SBrooks Davis
361*b0d29bc4SBrooks Davis
362*b0d29bc4SBrooks Davis ATF_TEST_CASE(dump_stacktrace__integration);
ATF_TEST_CASE_HEAD(dump_stacktrace__integration)363*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(dump_stacktrace__integration)
364*b0d29bc4SBrooks Davis {
365*b0d29bc4SBrooks Davis set_md_var("require.progs", utils::builtin_gdb);
366*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(dump_stacktrace__integration)367*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(dump_stacktrace__integration)
368*b0d29bc4SBrooks Davis {
369*b0d29bc4SBrooks Davis executor::executor_handle handle = executor::setup();
370*b0d29bc4SBrooks Davis
371*b0d29bc4SBrooks Davis executor::exit_handle exit_handle = generate_core(this, "short", handle);
372*b0d29bc4SBrooks Davis INV(exit_handle.status());
373*b0d29bc4SBrooks Davis INV(exit_handle.status().get().coredump());
374*b0d29bc4SBrooks Davis
375*b0d29bc4SBrooks Davis std::ostringstream output;
376*b0d29bc4SBrooks Davis utils::dump_stacktrace(fs::path("short"), handle, exit_handle);
377*b0d29bc4SBrooks Davis
378*b0d29bc4SBrooks Davis // It is hard to validate the execution of an arbitrary GDB of which we do
379*b0d29bc4SBrooks Davis // not know anything. Just assume that the backtrace, at the very least,
380*b0d29bc4SBrooks Davis // prints a couple of frame identifiers.
381*b0d29bc4SBrooks Davis ATF_REQUIRE(!atf::utils::grep_file("#0", exit_handle.stdout_file().str()));
382*b0d29bc4SBrooks Davis ATF_REQUIRE( atf::utils::grep_file("#0", exit_handle.stderr_file().str()));
383*b0d29bc4SBrooks Davis ATF_REQUIRE(!atf::utils::grep_file("#1", exit_handle.stdout_file().str()));
384*b0d29bc4SBrooks Davis ATF_REQUIRE( atf::utils::grep_file("#1", exit_handle.stderr_file().str()));
385*b0d29bc4SBrooks Davis
386*b0d29bc4SBrooks Davis exit_handle.cleanup();
387*b0d29bc4SBrooks Davis handle.cleanup();
388*b0d29bc4SBrooks Davis }
389*b0d29bc4SBrooks Davis
390*b0d29bc4SBrooks Davis
391*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(dump_stacktrace__ok);
ATF_TEST_CASE_BODY(dump_stacktrace__ok)392*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(dump_stacktrace__ok)
393*b0d29bc4SBrooks Davis {
394*b0d29bc4SBrooks Davis utils::setenv("PATH", ".");
395*b0d29bc4SBrooks Davis create_script("fake-gdb", "echo 'frame 1'; echo 'frame 2'; "
396*b0d29bc4SBrooks Davis "echo 'some warning' 1>&2; exit 0");
397*b0d29bc4SBrooks Davis utils::builtin_gdb = "fake-gdb";
398*b0d29bc4SBrooks Davis
399*b0d29bc4SBrooks Davis executor::executor_handle handle = executor::setup();
400*b0d29bc4SBrooks Davis executor::exit_handle exit_handle = generate_core(this, "short", handle);
401*b0d29bc4SBrooks Davis INV(exit_handle.status());
402*b0d29bc4SBrooks Davis INV(exit_handle.status().get().coredump());
403*b0d29bc4SBrooks Davis
404*b0d29bc4SBrooks Davis utils::dump_stacktrace(fs::path("short"), handle, exit_handle);
405*b0d29bc4SBrooks Davis
406*b0d29bc4SBrooks Davis // Note how all output is expected on stderr even for the messages that the
407*b0d29bc4SBrooks Davis // script decided to send to stdout.
408*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("exited with signal [0-9]* and dumped",
409*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
410*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("^frame 1$",
411*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
412*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("^frame 2$",
413*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
414*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("^some warning$",
415*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
416*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("GDB exited successfully",
417*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
418*b0d29bc4SBrooks Davis
419*b0d29bc4SBrooks Davis exit_handle.cleanup();
420*b0d29bc4SBrooks Davis handle.cleanup();
421*b0d29bc4SBrooks Davis }
422*b0d29bc4SBrooks Davis
423*b0d29bc4SBrooks Davis
424*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(dump_stacktrace__cannot_find_core);
ATF_TEST_CASE_BODY(dump_stacktrace__cannot_find_core)425*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(dump_stacktrace__cannot_find_core)
426*b0d29bc4SBrooks Davis {
427*b0d29bc4SBrooks Davis // Make sure we can find a GDB binary so that we don't fail the test for
428*b0d29bc4SBrooks Davis // the wrong reason.
429*b0d29bc4SBrooks Davis utils::setenv("PATH", ".");
430*b0d29bc4SBrooks Davis utils::builtin_gdb = "fake-gdb";
431*b0d29bc4SBrooks Davis atf::utils::create_file("fake-gdb", "unused");
432*b0d29bc4SBrooks Davis
433*b0d29bc4SBrooks Davis executor::executor_handle handle = executor::setup();
434*b0d29bc4SBrooks Davis executor::exit_handle exit_handle = generate_core(this, "short", handle);
435*b0d29bc4SBrooks Davis
436*b0d29bc4SBrooks Davis const optional< fs::path > core_name = utils::find_core(
437*b0d29bc4SBrooks Davis fs::path("short"),
438*b0d29bc4SBrooks Davis exit_handle.status().get(),
439*b0d29bc4SBrooks Davis exit_handle.work_directory());
440*b0d29bc4SBrooks Davis if (core_name) {
441*b0d29bc4SBrooks Davis // This is needed even if we provide a different basename to
442*b0d29bc4SBrooks Davis // dump_stacktrace below because the system policies may be generating
443*b0d29bc4SBrooks Davis // core dumps by PID, not binary name.
444*b0d29bc4SBrooks Davis std::cout << "Removing core dump: " << core_name << '\n';
445*b0d29bc4SBrooks Davis fs::unlink(core_name.get());
446*b0d29bc4SBrooks Davis }
447*b0d29bc4SBrooks Davis
448*b0d29bc4SBrooks Davis utils::dump_stacktrace(fs::path("fake"), handle, exit_handle);
449*b0d29bc4SBrooks Davis
450*b0d29bc4SBrooks Davis atf::utils::cat_file(exit_handle.stdout_file().str(), "stdout: ");
451*b0d29bc4SBrooks Davis atf::utils::cat_file(exit_handle.stderr_file().str(), "stderr: ");
452*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("Cannot find any core file",
453*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
454*b0d29bc4SBrooks Davis
455*b0d29bc4SBrooks Davis exit_handle.cleanup();
456*b0d29bc4SBrooks Davis handle.cleanup();
457*b0d29bc4SBrooks Davis }
458*b0d29bc4SBrooks Davis
459*b0d29bc4SBrooks Davis
460*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(dump_stacktrace__cannot_find_gdb);
ATF_TEST_CASE_BODY(dump_stacktrace__cannot_find_gdb)461*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(dump_stacktrace__cannot_find_gdb)
462*b0d29bc4SBrooks Davis {
463*b0d29bc4SBrooks Davis utils::setenv("PATH", ".");
464*b0d29bc4SBrooks Davis utils::builtin_gdb = "missing-gdb";
465*b0d29bc4SBrooks Davis
466*b0d29bc4SBrooks Davis executor::executor_handle handle = executor::setup();
467*b0d29bc4SBrooks Davis executor::exit_handle exit_handle = generate_core(this, "short", handle);
468*b0d29bc4SBrooks Davis
469*b0d29bc4SBrooks Davis utils::dump_stacktrace(fs::path("fake"), handle, exit_handle);
470*b0d29bc4SBrooks Davis
471*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file(
472*b0d29bc4SBrooks Davis "Cannot find GDB binary; builtin was 'missing-gdb'",
473*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
474*b0d29bc4SBrooks Davis
475*b0d29bc4SBrooks Davis exit_handle.cleanup();
476*b0d29bc4SBrooks Davis handle.cleanup();
477*b0d29bc4SBrooks Davis }
478*b0d29bc4SBrooks Davis
479*b0d29bc4SBrooks Davis
480*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(dump_stacktrace__gdb_fail);
ATF_TEST_CASE_BODY(dump_stacktrace__gdb_fail)481*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(dump_stacktrace__gdb_fail)
482*b0d29bc4SBrooks Davis {
483*b0d29bc4SBrooks Davis utils::setenv("PATH", ".");
484*b0d29bc4SBrooks Davis create_script("fake-gdb", "echo 'foo'; echo 'bar' 1>&2; exit 1");
485*b0d29bc4SBrooks Davis const std::string gdb = (fs::current_path() / "fake-gdb").str();
486*b0d29bc4SBrooks Davis utils::builtin_gdb = gdb.c_str();
487*b0d29bc4SBrooks Davis
488*b0d29bc4SBrooks Davis executor::executor_handle handle = executor::setup();
489*b0d29bc4SBrooks Davis executor::exit_handle exit_handle = generate_core(this, "short", handle);
490*b0d29bc4SBrooks Davis
491*b0d29bc4SBrooks Davis atf::utils::create_file((exit_handle.work_directory() / "fake.core").str(),
492*b0d29bc4SBrooks Davis "Invalid core file, but not read");
493*b0d29bc4SBrooks Davis utils::dump_stacktrace(fs::path("fake"), handle, exit_handle);
494*b0d29bc4SBrooks Davis
495*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("^foo$",
496*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
497*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("^bar$",
498*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
499*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("GDB failed; see output above",
500*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
501*b0d29bc4SBrooks Davis
502*b0d29bc4SBrooks Davis exit_handle.cleanup();
503*b0d29bc4SBrooks Davis handle.cleanup();
504*b0d29bc4SBrooks Davis }
505*b0d29bc4SBrooks Davis
506*b0d29bc4SBrooks Davis
507*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(dump_stacktrace__gdb_timeout);
ATF_TEST_CASE_BODY(dump_stacktrace__gdb_timeout)508*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(dump_stacktrace__gdb_timeout)
509*b0d29bc4SBrooks Davis {
510*b0d29bc4SBrooks Davis utils::setenv("PATH", ".");
511*b0d29bc4SBrooks Davis create_script("fake-gdb", "while :; do sleep 1; done");
512*b0d29bc4SBrooks Davis const std::string gdb = (fs::current_path() / "fake-gdb").str();
513*b0d29bc4SBrooks Davis utils::builtin_gdb = gdb.c_str();
514*b0d29bc4SBrooks Davis utils::gdb_timeout = datetime::delta(1, 0);
515*b0d29bc4SBrooks Davis
516*b0d29bc4SBrooks Davis executor::executor_handle handle = executor::setup();
517*b0d29bc4SBrooks Davis executor::exit_handle exit_handle = generate_core(this, "short", handle);
518*b0d29bc4SBrooks Davis
519*b0d29bc4SBrooks Davis atf::utils::create_file((exit_handle.work_directory() / "fake.core").str(),
520*b0d29bc4SBrooks Davis "Invalid core file, but not read");
521*b0d29bc4SBrooks Davis utils::dump_stacktrace(fs::path("fake"), handle, exit_handle);
522*b0d29bc4SBrooks Davis
523*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("GDB timed out",
524*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
525*b0d29bc4SBrooks Davis
526*b0d29bc4SBrooks Davis exit_handle.cleanup();
527*b0d29bc4SBrooks Davis handle.cleanup();
528*b0d29bc4SBrooks Davis }
529*b0d29bc4SBrooks Davis
530*b0d29bc4SBrooks Davis
531*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(dump_stacktrace_if_available__append);
ATF_TEST_CASE_BODY(dump_stacktrace_if_available__append)532*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(dump_stacktrace_if_available__append)
533*b0d29bc4SBrooks Davis {
534*b0d29bc4SBrooks Davis utils::setenv("PATH", ".");
535*b0d29bc4SBrooks Davis create_script("fake-gdb", "echo 'frame 1'; exit 0");
536*b0d29bc4SBrooks Davis utils::builtin_gdb = "fake-gdb";
537*b0d29bc4SBrooks Davis
538*b0d29bc4SBrooks Davis executor::executor_handle handle = executor::setup();
539*b0d29bc4SBrooks Davis executor::exit_handle exit_handle = generate_core(this, "short", handle);
540*b0d29bc4SBrooks Davis
541*b0d29bc4SBrooks Davis atf::utils::create_file(exit_handle.stdout_file().str(), "Pre-stdout");
542*b0d29bc4SBrooks Davis atf::utils::create_file(exit_handle.stderr_file().str(), "Pre-stderr");
543*b0d29bc4SBrooks Davis
544*b0d29bc4SBrooks Davis utils::dump_stacktrace_if_available(fs::path("short"), handle, exit_handle);
545*b0d29bc4SBrooks Davis
546*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("Pre-stdout",
547*b0d29bc4SBrooks Davis exit_handle.stdout_file().str()));
548*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("Pre-stderr",
549*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
550*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::grep_file("frame 1",
551*b0d29bc4SBrooks Davis exit_handle.stderr_file().str()));
552*b0d29bc4SBrooks Davis
553*b0d29bc4SBrooks Davis exit_handle.cleanup();
554*b0d29bc4SBrooks Davis handle.cleanup();
555*b0d29bc4SBrooks Davis }
556*b0d29bc4SBrooks Davis
557*b0d29bc4SBrooks Davis
558*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(dump_stacktrace_if_available__no_status);
ATF_TEST_CASE_BODY(dump_stacktrace_if_available__no_status)559*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(dump_stacktrace_if_available__no_status)
560*b0d29bc4SBrooks Davis {
561*b0d29bc4SBrooks Davis executor::executor_handle handle = executor::setup();
562*b0d29bc4SBrooks Davis const executor::exec_handle exec_handle = handle.spawn(
563*b0d29bc4SBrooks Davis child_pause, datetime::delta(0, 100000), none, none, none);
564*b0d29bc4SBrooks Davis executor::exit_handle exit_handle = handle.wait(exec_handle);
565*b0d29bc4SBrooks Davis INV(!exit_handle.status());
566*b0d29bc4SBrooks Davis
567*b0d29bc4SBrooks Davis utils::dump_stacktrace_if_available(fs::path("short"), handle, exit_handle);
568*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::compare_file(exit_handle.stdout_file().str(), ""));
569*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::compare_file(exit_handle.stderr_file().str(), ""));
570*b0d29bc4SBrooks Davis
571*b0d29bc4SBrooks Davis exit_handle.cleanup();
572*b0d29bc4SBrooks Davis handle.cleanup();
573*b0d29bc4SBrooks Davis }
574*b0d29bc4SBrooks Davis
575*b0d29bc4SBrooks Davis
576*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(dump_stacktrace_if_available__no_coredump);
ATF_TEST_CASE_BODY(dump_stacktrace_if_available__no_coredump)577*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(dump_stacktrace_if_available__no_coredump)
578*b0d29bc4SBrooks Davis {
579*b0d29bc4SBrooks Davis executor::executor_handle handle = executor::setup();
580*b0d29bc4SBrooks Davis const executor::exec_handle exec_handle = handle.spawn(
581*b0d29bc4SBrooks Davis child_exit, datetime::delta(60, 0), none, none, none);
582*b0d29bc4SBrooks Davis executor::exit_handle exit_handle = handle.wait(exec_handle);
583*b0d29bc4SBrooks Davis INV(exit_handle.status());
584*b0d29bc4SBrooks Davis INV(exit_handle.status().get().exited());
585*b0d29bc4SBrooks Davis INV(exit_handle.status().get().exitstatus() == EXIT_SUCCESS);
586*b0d29bc4SBrooks Davis
587*b0d29bc4SBrooks Davis utils::dump_stacktrace_if_available(fs::path("short"), handle, exit_handle);
588*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::compare_file(exit_handle.stdout_file().str(), ""));
589*b0d29bc4SBrooks Davis ATF_REQUIRE(atf::utils::compare_file(exit_handle.stderr_file().str(), ""));
590*b0d29bc4SBrooks Davis
591*b0d29bc4SBrooks Davis exit_handle.cleanup();
592*b0d29bc4SBrooks Davis handle.cleanup();
593*b0d29bc4SBrooks Davis }
594*b0d29bc4SBrooks Davis
595*b0d29bc4SBrooks Davis
ATF_INIT_TEST_CASES(tcs)596*b0d29bc4SBrooks Davis ATF_INIT_TEST_CASES(tcs)
597*b0d29bc4SBrooks Davis {
598*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, unlimit_core_size);
599*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, unlimit_core_size__hard_is_zero);
600*b0d29bc4SBrooks Davis
601*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, find_gdb__use_builtin);
602*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, find_gdb__search_builtin__ok);
603*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, find_gdb__search_builtin__fail);
604*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, find_gdb__bogus_value);
605*b0d29bc4SBrooks Davis
606*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, find_core__found__short);
607*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, find_core__found__long);
608*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, find_core__not_found);
609*b0d29bc4SBrooks Davis
610*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, dump_stacktrace__integration);
611*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, dump_stacktrace__ok);
612*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, dump_stacktrace__cannot_find_core);
613*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, dump_stacktrace__cannot_find_gdb);
614*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, dump_stacktrace__gdb_fail);
615*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, dump_stacktrace__gdb_timeout);
616*b0d29bc4SBrooks Davis
617*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, dump_stacktrace_if_available__append);
618*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, dump_stacktrace_if_available__no_status);
619*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, dump_stacktrace_if_available__no_coredump);
620*b0d29bc4SBrooks Davis }
621