tools/llvm: Do not build with symbols
[minix3.git] / external / bsd / kyua-testers / dist / stacktrace_test.c
blob969c9ecbd4ca17630626169116786e246f99638d
1 // Copyright 2012 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "stacktrace.h"
31 #include <sys/resource.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
39 #include <atf-c.h>
41 #include "env.h"
42 #include "error.h"
43 #include "fs.h"
44 #include "run.h"
45 #include "text.h"
48 /// Ensures that the given expression does not return a kyua_error_t.
49 ///
50 /// \param expr Expression to evaluate.
51 #define RE(expr) ATF_REQUIRE(!kyua_error_is_set(expr))
54 /// Ensures that the given expression does not return a kyua_error_t.
55 ///
56 /// \param expr Expression to evaluate.
57 /// \param msg Failure message.
58 #define RE_MSG(expr, msg) ATF_REQUIRE_MSG(!kyua_error_is_set(expr), msg)
61 /// Generates a core dump.
62 ///
63 /// Due to the complexity of this interface, you should probably use
64 /// generate_core() instead.
65 ///
66 /// \post If this fails to generate a core file, the test case is marked as
67 /// skipped. The caller therefore can rely that a core dump has been created on
68 /// return.
69 ///
70 /// \param tc Pointer to the caller test case.
71 /// \param run_params Parameters for the execution of the helper.
72 /// \param helper_path Path to the created helper.
73 /// \param exec_path Name of the helper, prefixed with ./ so that it can be
74 /// executed from within the work directory.
75 /// \param helper_name Basename of the helper.
76 ///
77 /// \return The PID of the crashed binary.
78 static pid_t
79 generate_core_aux(const atf_tc_t* tc, const kyua_run_params_t* run_params,
80 const char* helper_path, const char* exec_path,
81 const char* helper_name)
83 const char* srcdir = atf_tc_get_config_var(tc, "srcdir");
85 char* src_helper;
86 RE(kyua_fs_concat(&src_helper, srcdir, "stacktrace_helper", NULL));
87 atf_utils_copy_file(src_helper, helper_path);
88 free(src_helper);
90 // We use kyua_run_fork for this to better simulate the final use case of
91 // the stacktrace gathering, as test programs are run through these
92 // functions. Also, kyua_run_fork provides us with automatic unlimiting of
93 // resources so that core files can be generated.
95 pid_t pid;
96 const kyua_error_t error = kyua_run_fork(run_params, &pid);
97 if (!kyua_error_is_set(error) && pid == 0) {
98 const char* const args[] = { helper_name, NULL };
99 kyua_run_exec(exec_path, args);
101 RE(error);
103 int status; bool timed_out;
104 RE_MSG(kyua_run_wait(pid, &status, &timed_out),
105 "wait failed; unexpected problem during exec?");
107 ATF_REQUIRE(WIFSIGNALED(status));
108 if (!WCOREDUMP(status))
109 atf_tc_skip("Test failed to generate core dump");
110 return pid;
114 /// Creates a script.
116 /// \param script Path to the script to create.
117 /// \param contents Contents of the script.
118 static void
119 create_script(const char* script, const char* contents)
121 atf_utils_create_file(script, "#! /bin/sh\n\n%s\n", contents);
122 ATF_REQUIRE(chmod(script, 0755) != -1);
126 /// Generates a core file.
128 /// \param tc Pointer to the calling test case.
129 /// \param work_directory Name of the directory in which to place the binary
130 /// that will generate the stacktrace.
131 /// \param program_name Basename of the binary that will crash.
133 /// \return PID of the process that generated the core file.
134 static pid_t
135 generate_core(const atf_tc_t* tc, const char* work_directory,
136 const char* program_name)
138 kyua_run_params_t run_params;
139 kyua_run_params_init(&run_params);
140 if (strcmp(work_directory, ".") != 0) {
141 ATF_REQUIRE(mkdir(work_directory, 0755) != -1);
142 run_params.work_directory = work_directory;
145 char* copy_to; char* exec_path;
146 RE(kyua_text_printf(&copy_to, "%s/%s", work_directory, program_name));
147 RE(kyua_text_printf(&exec_path, "./%s", program_name));
148 const pid_t pid = generate_core_aux(tc, &run_params, copy_to, exec_path,
149 program_name);
150 free(exec_path);
151 free(copy_to);
152 return pid;
156 /// Prepares and runs kyua_stacktrace_dump().
158 /// \param tc Pointer to the calling test case.
159 /// \param work_directory Name of the directory in which to place the binary
160 /// that will generate the stacktrace.
161 /// \param program_name Basename of the binary that will crash.
162 /// \param output_name Name of the file to which to write the stacktrace.
163 /// \param timeout_seconds Time to give GDB to complete.
164 static void
165 do_dump(const atf_tc_t* tc, const char* work_directory,
166 const char* program_name, const char* output_name,
167 const int timeout_seconds)
169 const pid_t pid = generate_core(tc, work_directory, program_name);
171 kyua_run_params_t run_params;
172 kyua_run_params_init(&run_params);
173 run_params.timeout_seconds = timeout_seconds + 100; // Some large value.
174 run_params.work_directory = work_directory; // Created by generate_core.
176 kyua_stacktrace_gdb_timeout = timeout_seconds;
178 FILE* output = fopen(output_name, "w");
179 ATF_REQUIRE(output != NULL);
180 kyua_stacktrace_dump(program_name, pid, &run_params, output);
181 fclose(output);
182 atf_utils_cat_file(output_name, "dump output: ");
186 ATF_TC_WITHOUT_HEAD(find_core__found__short);
187 ATF_TC_BODY(find_core__found__short, tc)
189 const pid_t pid = generate_core(tc, "dir", "short");
190 const char* core_name = kyua_stacktrace_find_core("short", "dir", pid);
191 if (core_name == NULL)
192 atf_tc_fail("Core dumped, but no candidates found");
193 ATF_REQUIRE(strstr(core_name, "core") != NULL);
194 ATF_REQUIRE(access(core_name, F_OK) != -1);
198 ATF_TC_WITHOUT_HEAD(find_core__found__long);
199 ATF_TC_BODY(find_core__found__long, tc)
201 const pid_t pid = generate_core(
202 tc, "dir", "long-name-that-may-be-truncated-in-some-systems");
203 const char* core_name = kyua_stacktrace_find_core(
204 "long-name-that-may-be-truncated-in-some-systems", "dir", pid);
205 if (core_name == NULL)
206 atf_tc_fail("Core dumped, but no candidates found");
207 ATF_REQUIRE(strstr(core_name, "core") != NULL);
208 ATF_REQUIRE(access(core_name, F_OK) != -1);
212 ATF_TC_WITHOUT_HEAD(find_core__not_found);
213 ATF_TC_BODY(find_core__not_found, tc)
215 const char* core_name = kyua_stacktrace_find_core("missing", ".", 1);
216 if (core_name != NULL)
217 atf_tc_fail("Core not dumped, but candidate found: %s", core_name);
221 ATF_TC_WITHOUT_HEAD(dump__integration);
222 ATF_TC_BODY(dump__integration, tc)
224 do_dump(tc, "dir", "short", "stacktrace", 10);
226 // It is hard to validate the execution of an arbitrary GDB of which we know
227 // nothing anything. Just assume that the backtrace, at the very least,
228 // prints a frame identifier.
229 ATF_REQUIRE(atf_utils_grep_file("#0", "stacktrace"));
233 ATF_TC_WITHOUT_HEAD(dump__ok);
234 ATF_TC_BODY(dump__ok, tc)
236 RE(kyua_env_set("PATH", "."));
237 create_script("fake-gdb", "echo 'frame 1'; echo 'frame 2'; "
238 "echo 'some warning' 1>&2; exit 0");
239 kyua_stacktrace_gdb = "fake-gdb";
241 do_dump(tc, ".", "short", "stacktrace", 10);
243 ATF_REQUIRE(atf_utils_grep_file("dumped core; attempting to gather",
244 "stacktrace"));
245 ATF_REQUIRE(atf_utils_grep_file("frame 1", "stacktrace"));
246 ATF_REQUIRE(atf_utils_grep_file("frame 2", "stacktrace"));
247 ATF_REQUIRE(atf_utils_grep_file("some warning", "stacktrace"));
248 ATF_REQUIRE(atf_utils_grep_file("GDB exited successfully", "stacktrace"));
252 ATF_TC_WITHOUT_HEAD(dump__cannot_find_core);
253 ATF_TC_BODY(dump__cannot_find_core, tc)
255 kyua_run_params_t run_params;
256 kyua_run_params_init(&run_params);
258 FILE* output = fopen("stacktrace", "w");
259 ATF_REQUIRE(output != NULL);
260 // This assumes that init(8) has never core dumped.
261 kyua_stacktrace_dump("missing", 1, &run_params, output);
262 fclose(output);
263 atf_utils_cat_file("stacktrace", "dump output: ");
265 ATF_REQUIRE(atf_utils_grep_file("Cannot find any core file", "stacktrace"));
269 ATF_TC_WITHOUT_HEAD(dump__cannot_find_gdb);
270 ATF_TC_BODY(dump__cannot_find_gdb, tc)
272 RE(kyua_env_set("PATH", "."));
273 kyua_stacktrace_gdb = "missing-gdb";
275 do_dump(tc, ".", "dont-care", "stacktrace", 10);
277 ATF_REQUIRE(atf_utils_grep_file("execvp failed", "stacktrace"));
281 ATF_TC_WITHOUT_HEAD(dump__gdb_fail);
282 ATF_TC_BODY(dump__gdb_fail, tc)
284 RE(kyua_env_set("PATH", "."));
285 create_script("fake-gdb", "echo 'foo'; echo 'bar' 1>&2; exit 56");
286 kyua_stacktrace_gdb = "fake-gdb";
288 do_dump(tc, ".", "short", "stacktrace", 10);
290 ATF_REQUIRE(atf_utils_grep_file("foo", "stacktrace"));
291 ATF_REQUIRE(atf_utils_grep_file("bar", "stacktrace"));
292 ATF_REQUIRE(atf_utils_grep_file("GDB failed with code 56; see output above "
293 "for details", "stacktrace"));
297 ATF_TC_WITHOUT_HEAD(dump__gdb_times_out);
298 ATF_TC_BODY(dump__gdb_times_out, tc)
300 RE(kyua_env_set("PATH", "."));
301 create_script("fake-gdb", "echo 'foo'; echo 'bar' 1>&2; "
302 "/bin/sleep 10; /usr/bin/sleep 10; exit 0");
303 kyua_stacktrace_gdb = "fake-gdb";
305 do_dump(tc, ".", "short", "stacktrace", 1);
307 ATF_REQUIRE(atf_utils_grep_file("foo", "stacktrace"));
308 ATF_REQUIRE(atf_utils_grep_file("bar", "stacktrace"));
309 ATF_REQUIRE(atf_utils_grep_file("GDB failed; timed out", "stacktrace"));
313 ATF_TP_ADD_TCS(tp)
315 ATF_TP_ADD_TC(tp, find_core__found__short);
316 ATF_TP_ADD_TC(tp, find_core__found__long);
317 ATF_TP_ADD_TC(tp, find_core__not_found);
319 ATF_TP_ADD_TC(tp, dump__integration);
320 ATF_TP_ADD_TC(tp, dump__ok);
321 ATF_TP_ADD_TC(tp, dump__cannot_find_core);
322 ATF_TP_ADD_TC(tp, dump__cannot_find_gdb);
323 ATF_TP_ADD_TC(tp, dump__gdb_fail);
324 ATF_TP_ADD_TC(tp, dump__gdb_times_out);
326 return atf_no_error();