xref: /freebsd/lib/libproc/tests/proc_test.c (revision 1bdc41d25293032c4cba3940e17875d42e2cf797)
19351ac6dSMark Johnston /*-
2*1bdc41d2SMark Johnston  * Copyright (c) 2014-2017 Mark Johnston <markj@FreeBSD.org>
39351ac6dSMark Johnston  * All rights reserved.
49351ac6dSMark Johnston  *
59351ac6dSMark Johnston  * Redistribution and use in source and binary forms, with or without
69351ac6dSMark Johnston  * modification, are permitted provided that the following conditions
79351ac6dSMark Johnston  * are met:
89351ac6dSMark Johnston  * 1. Redistributions of source code must retain the above copyright
99351ac6dSMark Johnston  *    notice, this list of conditions and the following disclaimer.
109351ac6dSMark Johnston  * 2. Redistributions in binary form must reproduce the above copyright
119351ac6dSMark Johnston  *    notice, this list of conditions and the following disclaimer in the
129351ac6dSMark Johnston  *    documentation and/or other materials provided with the distribution.
139351ac6dSMark Johnston  *
149351ac6dSMark Johnston  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
159351ac6dSMark Johnston  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
169351ac6dSMark Johnston  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
179351ac6dSMark Johnston  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
189351ac6dSMark Johnston  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199351ac6dSMark Johnston  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
209351ac6dSMark Johnston  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
219351ac6dSMark Johnston  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
229351ac6dSMark Johnston  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
239351ac6dSMark Johnston  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
249351ac6dSMark Johnston  * SUCH DAMAGE.
259351ac6dSMark Johnston  */
269351ac6dSMark Johnston 
279351ac6dSMark Johnston #include <sys/cdefs.h>
289351ac6dSMark Johnston __FBSDID("$FreeBSD$");
299351ac6dSMark Johnston 
309351ac6dSMark Johnston #include <sys/types.h>
319351ac6dSMark Johnston #include <sys/wait.h>
329351ac6dSMark Johnston 
339351ac6dSMark Johnston #include <libgen.h>
349351ac6dSMark Johnston #include <stdio.h>
359351ac6dSMark Johnston #include <stdint.h>
369351ac6dSMark Johnston #include <stdlib.h>
379351ac6dSMark Johnston #include <string.h>
389351ac6dSMark Johnston #include <atf-c.h>
399351ac6dSMark Johnston #include <libelf.h>
409351ac6dSMark Johnston #include <libproc.h>
419351ac6dSMark Johnston 
429351ac6dSMark Johnston static const char *aout_object = "a.out";
439351ac6dSMark Johnston static const char *ldelf_object = "ld-elf.so.1";
449351ac6dSMark Johnston static const char *target_prog_file = "target_prog";
459351ac6dSMark Johnston 
469351ac6dSMark Johnston /*
479351ac6dSMark Johnston  * Run the test program. If the sig parameter is set to true, the test program
489351ac6dSMark Johnston  * will deliver SIGUSR1 to itself during execution.
499351ac6dSMark Johnston  */
509351ac6dSMark Johnston static struct proc_handle *
519351ac6dSMark Johnston start_prog(const struct atf_tc *tc, bool sig)
529351ac6dSMark Johnston {
539351ac6dSMark Johnston 	char *argv[3];
549351ac6dSMark Johnston 	struct proc_handle *phdl;
559351ac6dSMark Johnston 	int error;
569351ac6dSMark Johnston 
579351ac6dSMark Johnston 	asprintf(&argv[0], "%s/%s", atf_tc_get_config_var(tc, "srcdir"),
589351ac6dSMark Johnston 	    target_prog_file);
599351ac6dSMark Johnston 	ATF_REQUIRE(argv[0] != NULL);
609351ac6dSMark Johnston 
619351ac6dSMark Johnston 	if (sig) {
629351ac6dSMark Johnston 		argv[1] = strdup("-s");
639351ac6dSMark Johnston 		argv[2] = NULL;
649351ac6dSMark Johnston 	} else {
659351ac6dSMark Johnston 		argv[1] = NULL;
669351ac6dSMark Johnston 	}
679351ac6dSMark Johnston 
689351ac6dSMark Johnston 	error = proc_create(argv[0], argv, NULL, NULL, &phdl);
699351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to run '%s'", target_prog_file);
709351ac6dSMark Johnston 	ATF_REQUIRE(phdl != NULL);
719351ac6dSMark Johnston 
729351ac6dSMark Johnston 	free(argv[0]);
739351ac6dSMark Johnston 	free(argv[1]);
749351ac6dSMark Johnston 
759351ac6dSMark Johnston 	return (phdl);
769351ac6dSMark Johnston }
779351ac6dSMark Johnston 
789351ac6dSMark Johnston static void
799351ac6dSMark Johnston set_bkpt(struct proc_handle *phdl, uintptr_t addr, u_long *saved)
809351ac6dSMark Johnston {
819351ac6dSMark Johnston 	int error;
829351ac6dSMark Johnston 
839351ac6dSMark Johnston 	error = proc_bkptset(phdl, addr, saved);
849351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to set breakpoint at 0x%jx",
859351ac6dSMark Johnston 	    (uintmax_t)addr);
869351ac6dSMark Johnston }
879351ac6dSMark Johnston 
889351ac6dSMark Johnston static void
899351ac6dSMark Johnston remove_bkpt(struct proc_handle *phdl, uintptr_t addr, u_long val)
909351ac6dSMark Johnston {
919351ac6dSMark Johnston 	int error;
929351ac6dSMark Johnston 
939351ac6dSMark Johnston 	error = proc_bkptdel(phdl, addr, val);
949351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0,
959351ac6dSMark Johnston 	    "failed to delete breakpoint at 0x%jx", (uintmax_t)addr);
969351ac6dSMark Johnston 
979351ac6dSMark Johnston 	error = proc_regset(phdl, REG_PC, addr);
989351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to reset program counter");
999351ac6dSMark Johnston }
1009351ac6dSMark Johnston 
1019351ac6dSMark Johnston /*
1029351ac6dSMark Johnston  * Wait for the specified process to hit a breakpoint at the specified symbol.
1039351ac6dSMark Johnston  */
1049351ac6dSMark Johnston static void
1059351ac6dSMark Johnston verify_bkpt(struct proc_handle *phdl, GElf_Sym *sym, const char *symname,
1069351ac6dSMark Johnston     const char *mapname)
1079351ac6dSMark Johnston {
1089351ac6dSMark Johnston 	char mapbname[MAXPATHLEN], *name;
1099351ac6dSMark Johnston 	GElf_Sym tsym;
1109351ac6dSMark Johnston 	prmap_t *map;
1119351ac6dSMark Johnston 	size_t namesz;
1129351ac6dSMark Johnston 	u_long addr;
1139351ac6dSMark Johnston 	int error, state;
1149351ac6dSMark Johnston 
1159351ac6dSMark Johnston 	state = proc_wstatus(phdl);
1169351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(state, PS_STOP, "process has state %d", state);
1179351ac6dSMark Johnston 
1189351ac6dSMark Johnston 	/* Get the program counter and decrement it. */
1199351ac6dSMark Johnston 	error = proc_regget(phdl, REG_PC, &addr);
1209351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to obtain PC for '%s'",
1219351ac6dSMark Johnston 	    target_prog_file);
1229351ac6dSMark Johnston 	proc_bkptregadj(&addr);
1239351ac6dSMark Johnston 
1249351ac6dSMark Johnston 	/*
1259351ac6dSMark Johnston 	 * Make sure the PC matches the expected value obtained from the symbol
1269351ac6dSMark Johnston 	 * definition we looked up earlier.
1279351ac6dSMark Johnston 	 */
1289351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(addr, sym->st_value,
1299351ac6dSMark Johnston 	    "program counter 0x%lx doesn't match expected value 0x%jx",
1309351ac6dSMark Johnston 	    addr, (uintmax_t)sym->st_value);
1319351ac6dSMark Johnston 
1329351ac6dSMark Johnston 	/*
1339351ac6dSMark Johnston 	 * Ensure we can look up the r_debug_state symbol using its starting
1349351ac6dSMark Johnston 	 * address and that the resulting symbol matches the one we found using
1359351ac6dSMark Johnston 	 * a name lookup.
1369351ac6dSMark Johnston 	 */
1379351ac6dSMark Johnston 	namesz = strlen(symname) + 1;
1389351ac6dSMark Johnston 	name = malloc(namesz);
1399351ac6dSMark Johnston 	ATF_REQUIRE(name != NULL);
1409351ac6dSMark Johnston 
1419351ac6dSMark Johnston 	error = proc_addr2sym(phdl, addr, name, namesz, &tsym);
1429351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up symbol at 0x%lx", addr);
1439351ac6dSMark Johnston 	ATF_REQUIRE_EQ(memcmp(sym, &tsym, sizeof(*sym)), 0);
1449351ac6dSMark Johnston 	ATF_REQUIRE_EQ(strcmp(symname, name), 0);
1459351ac6dSMark Johnston 	free(name);
1469351ac6dSMark Johnston 
1479351ac6dSMark Johnston 	map = proc_addr2map(phdl, addr);
1489351ac6dSMark Johnston 	ATF_REQUIRE_MSG(map != NULL, "failed to look up map for address 0x%lx",
1499351ac6dSMark Johnston 	    addr);
1509351ac6dSMark Johnston 	basename_r(map->pr_mapname, mapbname);
1519351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(strcmp(mapname, mapbname), 0,
1529351ac6dSMark Johnston 	    "expected map name '%s' doesn't match '%s'", mapname, mapbname);
1539351ac6dSMark Johnston }
1549351ac6dSMark Johnston 
1559351ac6dSMark Johnston ATF_TC(map_alias_name2map);
1569351ac6dSMark Johnston ATF_TC_HEAD(map_alias_name2map, tc)
1579351ac6dSMark Johnston {
1589351ac6dSMark Johnston 	atf_tc_set_md_var(tc, "descr",
1599351ac6dSMark Johnston 	    "Callers are supposed to be able to use \"a.out\" as an alias for "
1609351ac6dSMark Johnston 	    "the program executable. Make sure that proc_name2map() handles "
1619351ac6dSMark Johnston 	    "this properly.");
1629351ac6dSMark Johnston }
1639351ac6dSMark Johnston ATF_TC_BODY(map_alias_name2map, tc)
1649351ac6dSMark Johnston {
1659351ac6dSMark Johnston 	struct proc_handle *phdl;
1669351ac6dSMark Johnston 	prmap_t *map1, *map2;
1679351ac6dSMark Johnston 
1689351ac6dSMark Johnston 	phdl = start_prog(tc, false);
1699351ac6dSMark Johnston 
1709351ac6dSMark Johnston 	/* Initialize the rtld_db handle. */
1719351ac6dSMark Johnston 	(void)proc_rdagent(phdl);
1729351ac6dSMark Johnston 
1739351ac6dSMark Johnston 	/* Ensure that "target_prog" and "a.out" return the same map. */
1749351ac6dSMark Johnston 	map1 = proc_name2map(phdl, target_prog_file);
1759351ac6dSMark Johnston 	ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for '%s'",
1769351ac6dSMark Johnston 	    target_prog_file);
1779351ac6dSMark Johnston 	map2 = proc_name2map(phdl, aout_object);
1789351ac6dSMark Johnston 	ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for '%s'",
1799351ac6dSMark Johnston 	    aout_object);
1809351ac6dSMark Johnston 	ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0);
1819351ac6dSMark Johnston 
1829351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
1839351ac6dSMark Johnston 
1849351ac6dSMark Johnston 	proc_free(phdl);
1859351ac6dSMark Johnston }
1869351ac6dSMark Johnston 
187d42df2a4SMark Johnston ATF_TC(map_prefix_name2map);
188d42df2a4SMark Johnston ATF_TC_HEAD(map_prefix_name2map, tc)
189d42df2a4SMark Johnston {
190d42df2a4SMark Johnston 	atf_tc_set_md_var(tc, "descr",
191d42df2a4SMark Johnston 	    "Verify that proc_name2map() returns prefix matches of the "
192d42df2a4SMark Johnston 	    "basename of loaded objects if no full matches are found.");
193d42df2a4SMark Johnston }
194d42df2a4SMark Johnston ATF_TC_BODY(map_prefix_name2map, tc)
195d42df2a4SMark Johnston {
196d42df2a4SMark Johnston 	struct proc_handle *phdl;
197d42df2a4SMark Johnston 	prmap_t *map1, *map2;
198d42df2a4SMark Johnston 
199d42df2a4SMark Johnston 	phdl = start_prog(tc, false);
200d42df2a4SMark Johnston 
201d42df2a4SMark Johnston 	/* Initialize the rtld_db handle. */
202d42df2a4SMark Johnston 	(void)proc_rdagent(phdl);
203d42df2a4SMark Johnston 
204d42df2a4SMark Johnston 	/* Make sure that "ld-elf" and "ld-elf.so" return the same map. */
205d42df2a4SMark Johnston 	map1 = proc_name2map(phdl, "ld-elf");
206d42df2a4SMark Johnston 	ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for 'ld-elf'");
207d42df2a4SMark Johnston 	map2 = proc_name2map(phdl, "ld-elf.so");
208d42df2a4SMark Johnston 	ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for 'ld-elf.so'");
209d42df2a4SMark Johnston 	ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0);
210d42df2a4SMark Johnston 
211d42df2a4SMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
212d42df2a4SMark Johnston 
213d42df2a4SMark Johnston 	proc_free(phdl);
214d42df2a4SMark Johnston }
215d42df2a4SMark Johnston 
2169351ac6dSMark Johnston ATF_TC(map_alias_name2sym);
2179351ac6dSMark Johnston ATF_TC_HEAD(map_alias_name2sym, tc)
2189351ac6dSMark Johnston {
2199351ac6dSMark Johnston 	atf_tc_set_md_var(tc, "descr",
2209351ac6dSMark Johnston 	    "Callers are supposed to be able to use \"a.out\" as an alias for "
2219351ac6dSMark Johnston 	    "the program executable. Make sure that proc_name2sym() handles "
2229351ac6dSMark Johnston 	    "this properly.");
2239351ac6dSMark Johnston }
2249351ac6dSMark Johnston ATF_TC_BODY(map_alias_name2sym, tc)
2259351ac6dSMark Johnston {
2269351ac6dSMark Johnston 	GElf_Sym sym1, sym2;
22741da933cSMark Johnston 	prsyminfo_t si1, si2;
2289351ac6dSMark Johnston 	struct proc_handle *phdl;
2299351ac6dSMark Johnston 	int error;
2309351ac6dSMark Johnston 
2319351ac6dSMark Johnston 	phdl = start_prog(tc, false);
2329351ac6dSMark Johnston 
2339351ac6dSMark Johnston 	/* Initialize the rtld_db handle. */
2349351ac6dSMark Johnston 	(void)proc_rdagent(phdl);
2359351ac6dSMark Johnston 
2369351ac6dSMark Johnston 	/*
2379351ac6dSMark Johnston 	 * Make sure that "target_prog:main" and "a.out:main" return the same
2389351ac6dSMark Johnston 	 * symbol.
2399351ac6dSMark Johnston 	 */
24041da933cSMark Johnston 	error = proc_name2sym(phdl, target_prog_file, "main", &sym1, &si1);
2419351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s",
2429351ac6dSMark Johnston 	    target_prog_file);
24341da933cSMark Johnston 	error = proc_name2sym(phdl, aout_object, "main", &sym2, &si2);
2449351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s",
2459351ac6dSMark Johnston 	    aout_object);
2469351ac6dSMark Johnston 
2479351ac6dSMark Johnston 	ATF_CHECK_EQ(memcmp(&sym1, &sym2, sizeof(sym1)), 0);
24841da933cSMark Johnston 	ATF_CHECK_EQ(si1.prs_id, si2.prs_id);
2499351ac6dSMark Johnston 
2509351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
2519351ac6dSMark Johnston 
2529351ac6dSMark Johnston 	proc_free(phdl);
2539351ac6dSMark Johnston }
2549351ac6dSMark Johnston 
2559351ac6dSMark Johnston ATF_TC(symbol_lookup);
2569351ac6dSMark Johnston ATF_TC_HEAD(symbol_lookup, tc)
2579351ac6dSMark Johnston {
2589351ac6dSMark Johnston 	atf_tc_set_md_var(tc, "descr",
2599351ac6dSMark Johnston 	    "Look up a couple of well-known symbols in the test program, place "
2609351ac6dSMark Johnston 	    "breakpoints on them, and verify that we hit the breakpoints. Also "
2619351ac6dSMark Johnston 	    "make sure that we can use the breakpoint address to look up the "
2629351ac6dSMark Johnston 	    "corresponding symbol.");
2639351ac6dSMark Johnston }
2649351ac6dSMark Johnston ATF_TC_BODY(symbol_lookup, tc)
2659351ac6dSMark Johnston {
2669351ac6dSMark Johnston 	GElf_Sym main_sym, r_debug_state_sym;
2679351ac6dSMark Johnston 	struct proc_handle *phdl;
2689351ac6dSMark Johnston 	u_long saved;
2699351ac6dSMark Johnston 	int error;
2709351ac6dSMark Johnston 
2719351ac6dSMark Johnston 	phdl = start_prog(tc, false);
2729351ac6dSMark Johnston 
27341da933cSMark Johnston 	error = proc_name2sym(phdl, target_prog_file, "main", &main_sym, NULL);
2749351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main'");
2759351ac6dSMark Johnston 
2769351ac6dSMark Johnston 	error = proc_name2sym(phdl, ldelf_object, "r_debug_state",
27741da933cSMark Johnston 	    &r_debug_state_sym, NULL);
2789351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'r_debug_state'");
2799351ac6dSMark Johnston 
2809351ac6dSMark Johnston 	set_bkpt(phdl, r_debug_state_sym.st_value, &saved);
2819351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
2829351ac6dSMark Johnston 	verify_bkpt(phdl, &r_debug_state_sym, "r_debug_state", ldelf_object);
2839351ac6dSMark Johnston 	remove_bkpt(phdl, r_debug_state_sym.st_value, saved);
2849351ac6dSMark Johnston 
2859351ac6dSMark Johnston 	set_bkpt(phdl, main_sym.st_value, &saved);
2869351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
2879351ac6dSMark Johnston 	verify_bkpt(phdl, &main_sym, "main", target_prog_file);
2889351ac6dSMark Johnston 	remove_bkpt(phdl, main_sym.st_value, saved);
2899351ac6dSMark Johnston 
2909351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
2919351ac6dSMark Johnston 
2929351ac6dSMark Johnston 	proc_free(phdl);
2939351ac6dSMark Johnston }
2949351ac6dSMark Johnston 
295cd9c9939SMark Johnston ATF_TC(symbol_lookup_fail);
296cd9c9939SMark Johnston ATF_TC_HEAD(symbol_lookup_fail, tc)
297cd9c9939SMark Johnston {
298cd9c9939SMark Johnston 	atf_tc_set_md_var(tc, "descr",
299cd9c9939SMark Johnston 	    "Verify that proc_addr2sym() returns an error when given an offset "
300cd9c9939SMark Johnston 	    "that it cannot resolve.");
301cd9c9939SMark Johnston }
302cd9c9939SMark Johnston ATF_TC_BODY(symbol_lookup_fail, tc)
303cd9c9939SMark Johnston {
304cd9c9939SMark Johnston 	char symname[32];
305cd9c9939SMark Johnston 	GElf_Sym sym;
306cd9c9939SMark Johnston 	struct proc_handle *phdl;
307cd9c9939SMark Johnston 	prmap_t *map;
308cd9c9939SMark Johnston 	int error;
309cd9c9939SMark Johnston 
310cd9c9939SMark Johnston 	phdl = start_prog(tc, false);
311cd9c9939SMark Johnston 
312cd9c9939SMark Johnston 	/* Initialize the rtld_db handle. */
313cd9c9939SMark Johnston 	(void)proc_rdagent(phdl);
314cd9c9939SMark Johnston 
315d42df2a4SMark Johnston 	map = proc_name2map(phdl, target_prog_file);
316cd9c9939SMark Johnston 	ATF_REQUIRE_MSG(map != NULL, "failed to look up map for '%s'",
317cd9c9939SMark Johnston 	    target_prog_file);
318cd9c9939SMark Johnston 
319cd9c9939SMark Johnston 	/*
320cd9c9939SMark Johnston 	 * We shouldn't be able to find symbols at the beginning of a mapped
321cd9c9939SMark Johnston 	 * file.
322cd9c9939SMark Johnston 	 */
323cd9c9939SMark Johnston 	error = proc_addr2sym(phdl, map->pr_vaddr, symname, sizeof(symname),
324cd9c9939SMark Johnston 	    &sym);
325cd9c9939SMark Johnston 	ATF_REQUIRE_MSG(error != 0, "unexpectedly found a symbol");
326cd9c9939SMark Johnston 
327cd9c9939SMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
328cd9c9939SMark Johnston 
329cd9c9939SMark Johnston 	proc_free(phdl);
330cd9c9939SMark Johnston }
331cd9c9939SMark Johnston 
3329351ac6dSMark Johnston ATF_TC(signal_forward);
3339351ac6dSMark Johnston ATF_TC_HEAD(signal_forward, tc)
3349351ac6dSMark Johnston {
3359351ac6dSMark Johnston 	atf_tc_set_md_var(tc, "descr",
3369351ac6dSMark Johnston 	    "Run the test program in a mode which causes it to send a signal "
3379351ac6dSMark Johnston 	    "to itself. Make sure that we intercept the signal and that "
3389351ac6dSMark Johnston 	    "proc_continue() forwards it to the process.");
3399351ac6dSMark Johnston }
3409351ac6dSMark Johnston ATF_TC_BODY(signal_forward, tc)
3419351ac6dSMark Johnston {
3429351ac6dSMark Johnston 	struct proc_handle *phdl;
3439351ac6dSMark Johnston 	int state, status;
3449351ac6dSMark Johnston 
3459351ac6dSMark Johnston 	phdl = start_prog(tc, true);
3469351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
3479351ac6dSMark Johnston 
3489351ac6dSMark Johnston 	/* The process should have been interrupted by a signal. */
3499351ac6dSMark Johnston 	state = proc_wstatus(phdl);
3509351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(state, PS_STOP, "process has unexpected state %d",
3519351ac6dSMark Johnston 	    state);
3529351ac6dSMark Johnston 
3539351ac6dSMark Johnston 	/* Continue execution and allow the signal to be delivered. */
3549351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
3559351ac6dSMark Johnston 
3569351ac6dSMark Johnston 	/*
3579351ac6dSMark Johnston 	 * Make sure the process exited with status 0. If it didn't receive the
3589351ac6dSMark Johnston 	 * SIGUSR1 that it sent to itself, it'll exit with a non-zero exit
3599351ac6dSMark Johnston 	 * status, causing the test to fail.
3609351ac6dSMark Johnston 	 */
3619351ac6dSMark Johnston 	state = proc_wstatus(phdl);
3629351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(state, PS_UNDEAD, "process has unexpected state %d",
3639351ac6dSMark Johnston 	    state);
3649351ac6dSMark Johnston 
3659351ac6dSMark Johnston 	status = proc_getwstat(phdl);
3669351ac6dSMark Johnston 	ATF_REQUIRE(status >= 0);
3679351ac6dSMark Johnston 	ATF_REQUIRE(WIFEXITED(status));
3689351ac6dSMark Johnston 	ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
3699351ac6dSMark Johnston 
3709351ac6dSMark Johnston 	proc_free(phdl);
3719351ac6dSMark Johnston }
3729351ac6dSMark Johnston 
373*1bdc41d2SMark Johnston ATF_TC(symbol_sort_local);
374*1bdc41d2SMark Johnston ATF_TC_HEAD(symbol_sort_local, tc)
375*1bdc41d2SMark Johnston {
376*1bdc41d2SMark Johnston 	atf_tc_set_md_var(tc, "descr",
377*1bdc41d2SMark Johnston 	    "Ensure that proc_addr2sym() returns the non-local alias when "
378*1bdc41d2SMark Johnston 	    "the address resolves to multiple symbols.");
379*1bdc41d2SMark Johnston }
380*1bdc41d2SMark Johnston ATF_TC_BODY(symbol_sort_local, tc)
381*1bdc41d2SMark Johnston {
382*1bdc41d2SMark Johnston 	char symname[32];
383*1bdc41d2SMark Johnston 	GElf_Sym bar_sym;
384*1bdc41d2SMark Johnston 	struct proc_handle *phdl;
385*1bdc41d2SMark Johnston 	int error;
386*1bdc41d2SMark Johnston 
387*1bdc41d2SMark Johnston 	phdl = start_prog(tc, true);
388*1bdc41d2SMark Johnston 
389*1bdc41d2SMark Johnston 	error = proc_name2sym(phdl, target_prog_file, "bar", &bar_sym, NULL);
390*1bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to look up 'bar' in %s",
391*1bdc41d2SMark Johnston 	    target_prog_file);
392*1bdc41d2SMark Johnston 	ATF_REQUIRE(GELF_ST_BIND(bar_sym.st_info) == STB_LOCAL);
393*1bdc41d2SMark Johnston 
394*1bdc41d2SMark Johnston 	error = proc_addr2sym(phdl, bar_sym.st_value, symname, sizeof(symname),
395*1bdc41d2SMark Johnston 	    &bar_sym);
396*1bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to resolve 'bar' by addr");
397*1bdc41d2SMark Johnston 
398*1bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(strcmp(symname, "baz") == 0,
399*1bdc41d2SMark Johnston 	    "unexpected symbol name '%s'", symname);
400*1bdc41d2SMark Johnston 	ATF_REQUIRE(GELF_ST_BIND(bar_sym.st_info) == STB_GLOBAL);
401*1bdc41d2SMark Johnston }
402*1bdc41d2SMark Johnston 
403*1bdc41d2SMark Johnston ATF_TC(symbol_sort_prefix);
404*1bdc41d2SMark Johnston ATF_TC_HEAD(symbol_sort_prefix, tc)
405*1bdc41d2SMark Johnston {
406*1bdc41d2SMark Johnston 	atf_tc_set_md_var(tc, "descr",
407*1bdc41d2SMark Johnston 	    "Ensure that proc_addr2sym() returns the alias whose name is not "
408*1bdc41d2SMark Johnston 	    "prefixed with '$' if one exists.");
409*1bdc41d2SMark Johnston }
410*1bdc41d2SMark Johnston ATF_TC_BODY(symbol_sort_prefix, tc)
411*1bdc41d2SMark Johnston {
412*1bdc41d2SMark Johnston 	char symname[32];
413*1bdc41d2SMark Johnston 	GElf_Sym qux_sym;
414*1bdc41d2SMark Johnston 	struct proc_handle *phdl;
415*1bdc41d2SMark Johnston 	int error;
416*1bdc41d2SMark Johnston 
417*1bdc41d2SMark Johnston 	phdl = start_prog(tc, true);
418*1bdc41d2SMark Johnston 
419*1bdc41d2SMark Johnston 	error = proc_name2sym(phdl, target_prog_file, "$qux", &qux_sym, NULL);
420*1bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to look up '$qux' in %s",
421*1bdc41d2SMark Johnston 	    target_prog_file);
422*1bdc41d2SMark Johnston 
423*1bdc41d2SMark Johnston 	error = proc_addr2sym(phdl, qux_sym.st_value, symname, sizeof(symname),
424*1bdc41d2SMark Johnston 	    &qux_sym);
425*1bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to resolve 'qux' by addr");
426*1bdc41d2SMark Johnston 
427*1bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(strcmp(symname, "qux") == 0,
428*1bdc41d2SMark Johnston 	    "unexpected symbol name '%s'", symname);
429*1bdc41d2SMark Johnston }
430*1bdc41d2SMark Johnston 
431*1bdc41d2SMark Johnston ATF_TC(symbol_sort_underscore);
432*1bdc41d2SMark Johnston ATF_TC_HEAD(symbol_sort_underscore, tc)
433*1bdc41d2SMark Johnston {
434*1bdc41d2SMark Johnston 	atf_tc_set_md_var(tc, "descr",
435*1bdc41d2SMark Johnston 	    "Ensure that proc_addr2sym() returns the alias with fewest leading "
436*1bdc41d2SMark Johnston 	    "underscores in the name when the address resolves to multiple "
437*1bdc41d2SMark Johnston 	    "symbols.");
438*1bdc41d2SMark Johnston }
439*1bdc41d2SMark Johnston ATF_TC_BODY(symbol_sort_underscore, tc)
440*1bdc41d2SMark Johnston {
441*1bdc41d2SMark Johnston 	char symname[32];
442*1bdc41d2SMark Johnston 	GElf_Sym foo_sym;
443*1bdc41d2SMark Johnston 	struct proc_handle *phdl;
444*1bdc41d2SMark Johnston 	int error;
445*1bdc41d2SMark Johnston 
446*1bdc41d2SMark Johnston 	phdl = start_prog(tc, true);
447*1bdc41d2SMark Johnston 
448*1bdc41d2SMark Johnston 	error = proc_name2sym(phdl, target_prog_file, "foo", &foo_sym, NULL);
449*1bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to look up 'foo' in %s",
450*1bdc41d2SMark Johnston 	    target_prog_file);
451*1bdc41d2SMark Johnston 
452*1bdc41d2SMark Johnston 	error = proc_addr2sym(phdl, foo_sym.st_value, symname, sizeof(symname),
453*1bdc41d2SMark Johnston 	    &foo_sym);
454*1bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to resolve 'foo' by addr");
455*1bdc41d2SMark Johnston 
456*1bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(strcmp(symname, "foo") == 0,
457*1bdc41d2SMark Johnston 	    "unexpected symbol name '%s'", symname);
458*1bdc41d2SMark Johnston }
459*1bdc41d2SMark Johnston 
4609351ac6dSMark Johnston ATF_TP_ADD_TCS(tp)
4619351ac6dSMark Johnston {
4629351ac6dSMark Johnston 
4639351ac6dSMark Johnston 	ATF_TP_ADD_TC(tp, map_alias_name2map);
464d42df2a4SMark Johnston 	ATF_TP_ADD_TC(tp, map_prefix_name2map);
4659351ac6dSMark Johnston 	ATF_TP_ADD_TC(tp, map_alias_name2sym);
4669351ac6dSMark Johnston 	ATF_TP_ADD_TC(tp, symbol_lookup);
467cd9c9939SMark Johnston 	ATF_TP_ADD_TC(tp, symbol_lookup_fail);
4689351ac6dSMark Johnston 	ATF_TP_ADD_TC(tp, signal_forward);
469*1bdc41d2SMark Johnston 	ATF_TP_ADD_TC(tp, symbol_sort_local);
470*1bdc41d2SMark Johnston 	ATF_TP_ADD_TC(tp, symbol_sort_prefix);
471*1bdc41d2SMark Johnston 	ATF_TP_ADD_TC(tp, symbol_sort_underscore);
4729351ac6dSMark Johnston 
4739351ac6dSMark Johnston 	return (atf_no_error());
4749351ac6dSMark Johnston }
475