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