xref: /freebsd/lib/libproc/tests/proc_test.c (revision 5577b8a709c072fedc73dde9b3ad730699438bf7)
19351ac6dSMark Johnston /*-
21bdc41d2SMark 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 
68*5577b8a7SMark Johnston 	error = proc_create(argv[0], argv, NULL, 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 {
1081bf4012cSEd Schouten 	char *name, *mapname_copy, *mapbname;
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);
1501bf4012cSEd Schouten 	mapname_copy = strdup(map->pr_mapname);
1511bf4012cSEd Schouten 	mapbname = basename(mapname_copy);
1529351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(strcmp(mapname, mapbname), 0,
1539351ac6dSMark Johnston 	    "expected map name '%s' doesn't match '%s'", mapname, mapbname);
1541bf4012cSEd Schouten 	free(mapname_copy);
1559351ac6dSMark Johnston }
1569351ac6dSMark Johnston 
1579351ac6dSMark Johnston ATF_TC(map_alias_name2map);
1589351ac6dSMark Johnston ATF_TC_HEAD(map_alias_name2map, tc)
1599351ac6dSMark Johnston {
1609351ac6dSMark Johnston 	atf_tc_set_md_var(tc, "descr",
1619351ac6dSMark Johnston 	    "Callers are supposed to be able to use \"a.out\" as an alias for "
1629351ac6dSMark Johnston 	    "the program executable. Make sure that proc_name2map() handles "
1639351ac6dSMark Johnston 	    "this properly.");
1649351ac6dSMark Johnston }
1659351ac6dSMark Johnston ATF_TC_BODY(map_alias_name2map, tc)
1669351ac6dSMark Johnston {
1679351ac6dSMark Johnston 	struct proc_handle *phdl;
1689351ac6dSMark Johnston 	prmap_t *map1, *map2;
1699351ac6dSMark Johnston 
1709351ac6dSMark Johnston 	phdl = start_prog(tc, false);
1719351ac6dSMark Johnston 
1729351ac6dSMark Johnston 	/* Initialize the rtld_db handle. */
1739351ac6dSMark Johnston 	(void)proc_rdagent(phdl);
1749351ac6dSMark Johnston 
1759351ac6dSMark Johnston 	/* Ensure that "target_prog" and "a.out" return the same map. */
1769351ac6dSMark Johnston 	map1 = proc_name2map(phdl, target_prog_file);
1779351ac6dSMark Johnston 	ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for '%s'",
1789351ac6dSMark Johnston 	    target_prog_file);
1799351ac6dSMark Johnston 	map2 = proc_name2map(phdl, aout_object);
1809351ac6dSMark Johnston 	ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for '%s'",
1819351ac6dSMark Johnston 	    aout_object);
1829351ac6dSMark Johnston 	ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0);
1839351ac6dSMark Johnston 
1849351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
1859351ac6dSMark Johnston 
1869351ac6dSMark Johnston 	proc_free(phdl);
1879351ac6dSMark Johnston }
1889351ac6dSMark Johnston 
189d42df2a4SMark Johnston ATF_TC(map_prefix_name2map);
190d42df2a4SMark Johnston ATF_TC_HEAD(map_prefix_name2map, tc)
191d42df2a4SMark Johnston {
192d42df2a4SMark Johnston 	atf_tc_set_md_var(tc, "descr",
193d42df2a4SMark Johnston 	    "Verify that proc_name2map() returns prefix matches of the "
194d42df2a4SMark Johnston 	    "basename of loaded objects if no full matches are found.");
195d42df2a4SMark Johnston }
196d42df2a4SMark Johnston ATF_TC_BODY(map_prefix_name2map, tc)
197d42df2a4SMark Johnston {
198d42df2a4SMark Johnston 	struct proc_handle *phdl;
199d42df2a4SMark Johnston 	prmap_t *map1, *map2;
200d42df2a4SMark Johnston 
201d42df2a4SMark Johnston 	phdl = start_prog(tc, false);
202d42df2a4SMark Johnston 
203d42df2a4SMark Johnston 	/* Initialize the rtld_db handle. */
204d42df2a4SMark Johnston 	(void)proc_rdagent(phdl);
205d42df2a4SMark Johnston 
206d42df2a4SMark Johnston 	/* Make sure that "ld-elf" and "ld-elf.so" return the same map. */
207d42df2a4SMark Johnston 	map1 = proc_name2map(phdl, "ld-elf");
208d42df2a4SMark Johnston 	ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for 'ld-elf'");
209d42df2a4SMark Johnston 	map2 = proc_name2map(phdl, "ld-elf.so");
210d42df2a4SMark Johnston 	ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for 'ld-elf.so'");
211d42df2a4SMark Johnston 	ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0);
212d42df2a4SMark Johnston 
213d42df2a4SMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
214d42df2a4SMark Johnston 
215d42df2a4SMark Johnston 	proc_free(phdl);
216d42df2a4SMark Johnston }
217d42df2a4SMark Johnston 
2189351ac6dSMark Johnston ATF_TC(map_alias_name2sym);
2199351ac6dSMark Johnston ATF_TC_HEAD(map_alias_name2sym, tc)
2209351ac6dSMark Johnston {
2219351ac6dSMark Johnston 	atf_tc_set_md_var(tc, "descr",
2229351ac6dSMark Johnston 	    "Callers are supposed to be able to use \"a.out\" as an alias for "
2239351ac6dSMark Johnston 	    "the program executable. Make sure that proc_name2sym() handles "
2249351ac6dSMark Johnston 	    "this properly.");
2259351ac6dSMark Johnston }
2269351ac6dSMark Johnston ATF_TC_BODY(map_alias_name2sym, tc)
2279351ac6dSMark Johnston {
2289351ac6dSMark Johnston 	GElf_Sym sym1, sym2;
22941da933cSMark Johnston 	prsyminfo_t si1, si2;
2309351ac6dSMark Johnston 	struct proc_handle *phdl;
2319351ac6dSMark Johnston 	int error;
2329351ac6dSMark Johnston 
2339351ac6dSMark Johnston 	phdl = start_prog(tc, false);
2349351ac6dSMark Johnston 
2359351ac6dSMark Johnston 	/* Initialize the rtld_db handle. */
2369351ac6dSMark Johnston 	(void)proc_rdagent(phdl);
2379351ac6dSMark Johnston 
2389351ac6dSMark Johnston 	/*
2399351ac6dSMark Johnston 	 * Make sure that "target_prog:main" and "a.out:main" return the same
2409351ac6dSMark Johnston 	 * symbol.
2419351ac6dSMark Johnston 	 */
24241da933cSMark Johnston 	error = proc_name2sym(phdl, target_prog_file, "main", &sym1, &si1);
2439351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s",
2449351ac6dSMark Johnston 	    target_prog_file);
24541da933cSMark Johnston 	error = proc_name2sym(phdl, aout_object, "main", &sym2, &si2);
2469351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s",
2479351ac6dSMark Johnston 	    aout_object);
2489351ac6dSMark Johnston 
2499351ac6dSMark Johnston 	ATF_CHECK_EQ(memcmp(&sym1, &sym2, sizeof(sym1)), 0);
25041da933cSMark Johnston 	ATF_CHECK_EQ(si1.prs_id, si2.prs_id);
2519351ac6dSMark Johnston 
2529351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
2539351ac6dSMark Johnston 
2549351ac6dSMark Johnston 	proc_free(phdl);
2559351ac6dSMark Johnston }
2569351ac6dSMark Johnston 
2579351ac6dSMark Johnston ATF_TC(symbol_lookup);
2589351ac6dSMark Johnston ATF_TC_HEAD(symbol_lookup, tc)
2599351ac6dSMark Johnston {
2609351ac6dSMark Johnston 	atf_tc_set_md_var(tc, "descr",
2619351ac6dSMark Johnston 	    "Look up a couple of well-known symbols in the test program, place "
2629351ac6dSMark Johnston 	    "breakpoints on them, and verify that we hit the breakpoints. Also "
2639351ac6dSMark Johnston 	    "make sure that we can use the breakpoint address to look up the "
2649351ac6dSMark Johnston 	    "corresponding symbol.");
2659351ac6dSMark Johnston }
2669351ac6dSMark Johnston ATF_TC_BODY(symbol_lookup, tc)
2679351ac6dSMark Johnston {
2689351ac6dSMark Johnston 	GElf_Sym main_sym, r_debug_state_sym;
2699351ac6dSMark Johnston 	struct proc_handle *phdl;
2709351ac6dSMark Johnston 	u_long saved;
2719351ac6dSMark Johnston 	int error;
2729351ac6dSMark Johnston 
2739351ac6dSMark Johnston 	phdl = start_prog(tc, false);
2749351ac6dSMark Johnston 
27541da933cSMark Johnston 	error = proc_name2sym(phdl, target_prog_file, "main", &main_sym, NULL);
2769351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main'");
2779351ac6dSMark Johnston 
2789351ac6dSMark Johnston 	error = proc_name2sym(phdl, ldelf_object, "r_debug_state",
27941da933cSMark Johnston 	    &r_debug_state_sym, NULL);
2809351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'r_debug_state'");
2819351ac6dSMark Johnston 
2829351ac6dSMark Johnston 	set_bkpt(phdl, r_debug_state_sym.st_value, &saved);
2839351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
2849351ac6dSMark Johnston 	verify_bkpt(phdl, &r_debug_state_sym, "r_debug_state", ldelf_object);
2859351ac6dSMark Johnston 	remove_bkpt(phdl, r_debug_state_sym.st_value, saved);
2869351ac6dSMark Johnston 
2879351ac6dSMark Johnston 	set_bkpt(phdl, main_sym.st_value, &saved);
2889351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
2899351ac6dSMark Johnston 	verify_bkpt(phdl, &main_sym, "main", target_prog_file);
2909351ac6dSMark Johnston 	remove_bkpt(phdl, main_sym.st_value, saved);
2919351ac6dSMark Johnston 
2929351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
2939351ac6dSMark Johnston 
2949351ac6dSMark Johnston 	proc_free(phdl);
2959351ac6dSMark Johnston }
2969351ac6dSMark Johnston 
297cd9c9939SMark Johnston ATF_TC(symbol_lookup_fail);
298cd9c9939SMark Johnston ATF_TC_HEAD(symbol_lookup_fail, tc)
299cd9c9939SMark Johnston {
300cd9c9939SMark Johnston 	atf_tc_set_md_var(tc, "descr",
301cd9c9939SMark Johnston 	    "Verify that proc_addr2sym() returns an error when given an offset "
302cd9c9939SMark Johnston 	    "that it cannot resolve.");
303cd9c9939SMark Johnston }
304cd9c9939SMark Johnston ATF_TC_BODY(symbol_lookup_fail, tc)
305cd9c9939SMark Johnston {
306cd9c9939SMark Johnston 	char symname[32];
307cd9c9939SMark Johnston 	GElf_Sym sym;
308cd9c9939SMark Johnston 	struct proc_handle *phdl;
309cd9c9939SMark Johnston 	prmap_t *map;
310cd9c9939SMark Johnston 	int error;
311cd9c9939SMark Johnston 
312cd9c9939SMark Johnston 	phdl = start_prog(tc, false);
313cd9c9939SMark Johnston 
314cd9c9939SMark Johnston 	/* Initialize the rtld_db handle. */
315cd9c9939SMark Johnston 	(void)proc_rdagent(phdl);
316cd9c9939SMark Johnston 
317d42df2a4SMark Johnston 	map = proc_name2map(phdl, target_prog_file);
318cd9c9939SMark Johnston 	ATF_REQUIRE_MSG(map != NULL, "failed to look up map for '%s'",
319cd9c9939SMark Johnston 	    target_prog_file);
320cd9c9939SMark Johnston 
321cd9c9939SMark Johnston 	/*
322cd9c9939SMark Johnston 	 * We shouldn't be able to find symbols at the beginning of a mapped
323cd9c9939SMark Johnston 	 * file.
324cd9c9939SMark Johnston 	 */
325cd9c9939SMark Johnston 	error = proc_addr2sym(phdl, map->pr_vaddr, symname, sizeof(symname),
326cd9c9939SMark Johnston 	    &sym);
327cd9c9939SMark Johnston 	ATF_REQUIRE_MSG(error != 0, "unexpectedly found a symbol");
328cd9c9939SMark Johnston 
329cd9c9939SMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
330cd9c9939SMark Johnston 
331cd9c9939SMark Johnston 	proc_free(phdl);
332cd9c9939SMark Johnston }
333cd9c9939SMark Johnston 
3349351ac6dSMark Johnston ATF_TC(signal_forward);
3359351ac6dSMark Johnston ATF_TC_HEAD(signal_forward, tc)
3369351ac6dSMark Johnston {
3379351ac6dSMark Johnston 	atf_tc_set_md_var(tc, "descr",
3389351ac6dSMark Johnston 	    "Run the test program in a mode which causes it to send a signal "
3399351ac6dSMark Johnston 	    "to itself. Make sure that we intercept the signal and that "
3409351ac6dSMark Johnston 	    "proc_continue() forwards it to the process.");
3419351ac6dSMark Johnston }
3429351ac6dSMark Johnston ATF_TC_BODY(signal_forward, tc)
3439351ac6dSMark Johnston {
3449351ac6dSMark Johnston 	struct proc_handle *phdl;
3459351ac6dSMark Johnston 	int state, status;
3469351ac6dSMark Johnston 
3479351ac6dSMark Johnston 	phdl = start_prog(tc, true);
3489351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
3499351ac6dSMark Johnston 
3509351ac6dSMark Johnston 	/* The process should have been interrupted by a signal. */
3519351ac6dSMark Johnston 	state = proc_wstatus(phdl);
3529351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(state, PS_STOP, "process has unexpected state %d",
3539351ac6dSMark Johnston 	    state);
3549351ac6dSMark Johnston 
3559351ac6dSMark Johnston 	/* Continue execution and allow the signal to be delivered. */
3569351ac6dSMark Johnston 	ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
3579351ac6dSMark Johnston 
3589351ac6dSMark Johnston 	/*
3599351ac6dSMark Johnston 	 * Make sure the process exited with status 0. If it didn't receive the
3609351ac6dSMark Johnston 	 * SIGUSR1 that it sent to itself, it'll exit with a non-zero exit
3619351ac6dSMark Johnston 	 * status, causing the test to fail.
3629351ac6dSMark Johnston 	 */
3639351ac6dSMark Johnston 	state = proc_wstatus(phdl);
3649351ac6dSMark Johnston 	ATF_REQUIRE_EQ_MSG(state, PS_UNDEAD, "process has unexpected state %d",
3659351ac6dSMark Johnston 	    state);
3669351ac6dSMark Johnston 
3679351ac6dSMark Johnston 	status = proc_getwstat(phdl);
3689351ac6dSMark Johnston 	ATF_REQUIRE(status >= 0);
3699351ac6dSMark Johnston 	ATF_REQUIRE(WIFEXITED(status));
3709351ac6dSMark Johnston 	ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
3719351ac6dSMark Johnston 
3729351ac6dSMark Johnston 	proc_free(phdl);
3739351ac6dSMark Johnston }
3749351ac6dSMark Johnston 
3751bdc41d2SMark Johnston ATF_TC(symbol_sort_local);
3761bdc41d2SMark Johnston ATF_TC_HEAD(symbol_sort_local, tc)
3771bdc41d2SMark Johnston {
3781bdc41d2SMark Johnston 	atf_tc_set_md_var(tc, "descr",
3791bdc41d2SMark Johnston 	    "Ensure that proc_addr2sym() returns the non-local alias when "
3801bdc41d2SMark Johnston 	    "the address resolves to multiple symbols.");
3811bdc41d2SMark Johnston }
3821bdc41d2SMark Johnston ATF_TC_BODY(symbol_sort_local, tc)
3831bdc41d2SMark Johnston {
3841bdc41d2SMark Johnston 	char symname[32];
3851bdc41d2SMark Johnston 	GElf_Sym bar_sym;
3861bdc41d2SMark Johnston 	struct proc_handle *phdl;
3871bdc41d2SMark Johnston 	int error;
3881bdc41d2SMark Johnston 
3891bdc41d2SMark Johnston 	phdl = start_prog(tc, true);
3901bdc41d2SMark Johnston 
3911bdc41d2SMark Johnston 	error = proc_name2sym(phdl, target_prog_file, "bar", &bar_sym, NULL);
3921bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to look up 'bar' in %s",
3931bdc41d2SMark Johnston 	    target_prog_file);
3941bdc41d2SMark Johnston 	ATF_REQUIRE(GELF_ST_BIND(bar_sym.st_info) == STB_LOCAL);
3951bdc41d2SMark Johnston 
3961bdc41d2SMark Johnston 	error = proc_addr2sym(phdl, bar_sym.st_value, symname, sizeof(symname),
3971bdc41d2SMark Johnston 	    &bar_sym);
3981bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to resolve 'bar' by addr");
3991bdc41d2SMark Johnston 
4001bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(strcmp(symname, "baz") == 0,
4011bdc41d2SMark Johnston 	    "unexpected symbol name '%s'", symname);
4021bdc41d2SMark Johnston 	ATF_REQUIRE(GELF_ST_BIND(bar_sym.st_info) == STB_GLOBAL);
4031bdc41d2SMark Johnston }
4041bdc41d2SMark Johnston 
4051bdc41d2SMark Johnston ATF_TC(symbol_sort_prefix);
4061bdc41d2SMark Johnston ATF_TC_HEAD(symbol_sort_prefix, tc)
4071bdc41d2SMark Johnston {
4081bdc41d2SMark Johnston 	atf_tc_set_md_var(tc, "descr",
4091bdc41d2SMark Johnston 	    "Ensure that proc_addr2sym() returns the alias whose name is not "
4101bdc41d2SMark Johnston 	    "prefixed with '$' if one exists.");
4111bdc41d2SMark Johnston }
4121bdc41d2SMark Johnston ATF_TC_BODY(symbol_sort_prefix, tc)
4131bdc41d2SMark Johnston {
4141bdc41d2SMark Johnston 	char symname[32];
4151bdc41d2SMark Johnston 	GElf_Sym qux_sym;
4161bdc41d2SMark Johnston 	struct proc_handle *phdl;
4171bdc41d2SMark Johnston 	int error;
4181bdc41d2SMark Johnston 
4191bdc41d2SMark Johnston 	phdl = start_prog(tc, true);
4201bdc41d2SMark Johnston 
4211bdc41d2SMark Johnston 	error = proc_name2sym(phdl, target_prog_file, "$qux", &qux_sym, NULL);
4221bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to look up '$qux' in %s",
4231bdc41d2SMark Johnston 	    target_prog_file);
4241bdc41d2SMark Johnston 
4251bdc41d2SMark Johnston 	error = proc_addr2sym(phdl, qux_sym.st_value, symname, sizeof(symname),
4261bdc41d2SMark Johnston 	    &qux_sym);
4271bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to resolve 'qux' by addr");
4281bdc41d2SMark Johnston 
4291bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(strcmp(symname, "qux") == 0,
4301bdc41d2SMark Johnston 	    "unexpected symbol name '%s'", symname);
4311bdc41d2SMark Johnston }
4321bdc41d2SMark Johnston 
4331bdc41d2SMark Johnston ATF_TC(symbol_sort_underscore);
4341bdc41d2SMark Johnston ATF_TC_HEAD(symbol_sort_underscore, tc)
4351bdc41d2SMark Johnston {
4361bdc41d2SMark Johnston 	atf_tc_set_md_var(tc, "descr",
4371bdc41d2SMark Johnston 	    "Ensure that proc_addr2sym() returns the alias with fewest leading "
4381bdc41d2SMark Johnston 	    "underscores in the name when the address resolves to multiple "
4391bdc41d2SMark Johnston 	    "symbols.");
4401bdc41d2SMark Johnston }
4411bdc41d2SMark Johnston ATF_TC_BODY(symbol_sort_underscore, tc)
4421bdc41d2SMark Johnston {
4431bdc41d2SMark Johnston 	char symname[32];
4441bdc41d2SMark Johnston 	GElf_Sym foo_sym;
4451bdc41d2SMark Johnston 	struct proc_handle *phdl;
4461bdc41d2SMark Johnston 	int error;
4471bdc41d2SMark Johnston 
4481bdc41d2SMark Johnston 	phdl = start_prog(tc, true);
4491bdc41d2SMark Johnston 
4501bdc41d2SMark Johnston 	error = proc_name2sym(phdl, target_prog_file, "foo", &foo_sym, NULL);
4511bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to look up 'foo' in %s",
4521bdc41d2SMark Johnston 	    target_prog_file);
4531bdc41d2SMark Johnston 
4541bdc41d2SMark Johnston 	error = proc_addr2sym(phdl, foo_sym.st_value, symname, sizeof(symname),
4551bdc41d2SMark Johnston 	    &foo_sym);
4561bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "failed to resolve 'foo' by addr");
4571bdc41d2SMark Johnston 
4581bdc41d2SMark Johnston 	ATF_REQUIRE_MSG(strcmp(symname, "foo") == 0,
4591bdc41d2SMark Johnston 	    "unexpected symbol name '%s'", symname);
4601bdc41d2SMark Johnston }
4611bdc41d2SMark Johnston 
4629351ac6dSMark Johnston ATF_TP_ADD_TCS(tp)
4639351ac6dSMark Johnston {
4649351ac6dSMark Johnston 
4659351ac6dSMark Johnston 	ATF_TP_ADD_TC(tp, map_alias_name2map);
466d42df2a4SMark Johnston 	ATF_TP_ADD_TC(tp, map_prefix_name2map);
4679351ac6dSMark Johnston 	ATF_TP_ADD_TC(tp, map_alias_name2sym);
4689351ac6dSMark Johnston 	ATF_TP_ADD_TC(tp, symbol_lookup);
469cd9c9939SMark Johnston 	ATF_TP_ADD_TC(tp, symbol_lookup_fail);
4709351ac6dSMark Johnston 	ATF_TP_ADD_TC(tp, signal_forward);
4711bdc41d2SMark Johnston 	ATF_TP_ADD_TC(tp, symbol_sort_local);
4721bdc41d2SMark Johnston 	ATF_TP_ADD_TC(tp, symbol_sort_prefix);
4731bdc41d2SMark Johnston 	ATF_TP_ADD_TC(tp, symbol_sort_underscore);
4749351ac6dSMark Johnston 
4759351ac6dSMark Johnston 	return (atf_no_error());
4769351ac6dSMark Johnston }
477