summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnji Cooper <ngie@FreeBSD.org>2017-01-14 06:18:54 +0000
committerEnji Cooper <ngie@FreeBSD.org>2017-01-14 06:18:54 +0000
commita567518138e0e2fa7177c60e241e8b8e4bb468d5 (patch)
tree0427e347dc09d7fa74ae68b4c1eca52840bf9f76
parenta72f1252fc5ae69e7e7690fce28695d5e6e37db1 (diff)
downloadsrc-test2-a567518138e0e2fa7177c60e241e8b8e4bb468d5.tar.gz
src-test2-a567518138e0e2fa7177c60e241e8b8e4bb468d5.zip
Notes
-rwxr-xr-xdev/clock_subr/clock_subr_test_data_gen.sh25
-rw-r--r--dev/clock_subr/t_clock_subr.c309
-rw-r--r--kernel/arch/amd64/t_ptrace_wait.c1388
-rw-r--r--kernel/arch/amd64/t_ptrace_wait3.c30
-rw-r--r--kernel/arch/amd64/t_ptrace_wait4.c30
-rw-r--r--kernel/arch/amd64/t_ptrace_wait6.c30
-rw-r--r--kernel/arch/amd64/t_ptrace_waitid.c30
-rw-r--r--kernel/arch/amd64/t_ptrace_waitpid.c30
-rw-r--r--kernel/arch/i386/t_ptrace_wait.c141
-rw-r--r--kernel/arch/i386/t_ptrace_wait3.c30
-rw-r--r--kernel/arch/i386/t_ptrace_wait4.c30
-rw-r--r--kernel/arch/i386/t_ptrace_wait6.c30
-rw-r--r--kernel/arch/i386/t_ptrace_waitid.c30
-rw-r--r--kernel/arch/i386/t_ptrace_waitpid.c30
-rw-r--r--kernel/t_ptrace_wait.c118
-rw-r--r--lib/libc/gen/exect/t_exect.c90
-rw-r--r--lib/libpthread_dbg/h_common.h128
-rw-r--r--lib/libpthread_dbg/t_dummy.c131
-rw-r--r--lib/libpthread_dbg/t_threads.c719
-rw-r--r--lib/librefuse/t_refuse_opt.c418
-rwxr-xr-xnet/if_tun/t_tun.sh138
-rwxr-xr-xnet/if_vlan/t_vlan.sh115
-rw-r--r--sys/uvm/t_uvm_physseg.c2377
-rw-r--r--sys/uvm/t_uvm_physseg_load.c740
-rwxr-xr-xusr.bin/mixerctl/t_mixerctl.sh51
-rw-r--r--usr.bin/uniq/d_basic.in4
-rw-r--r--usr.bin/uniq/d_basic.out3
-rw-r--r--usr.bin/uniq/d_counts.out6
-rw-r--r--usr.bin/uniq/d_input.in7
-rw-r--r--usr.bin/uniq/d_show_duplicates.out1
-rw-r--r--usr.bin/uniq/d_show_uniques.out5
-rwxr-xr-xusr.bin/uniq/t_uniq.sh97
32 files changed, 7309 insertions, 2 deletions
diff --git a/dev/clock_subr/clock_subr_test_data_gen.sh b/dev/clock_subr/clock_subr_test_data_gen.sh
new file mode 100755
index 000000000000..2da21a8da1bd
--- /dev/null
+++ b/dev/clock_subr/clock_subr_test_data_gen.sh
@@ -0,0 +1,25 @@
+#!/bin/ksh
+
+export TZ=Etc/Universal
+
+datesub() {
+ gdate "$@" '+ FILL(%_11s,%_4Y,%_m,%_d,%w,%_H,%_M,%_S), // %a %b %e %H:%M:%S %Z %Y'
+}
+
+(
+ datesub -d '1970/01/01 00:00:00'
+ datesub -d '1981/04/12 12:00:03'
+ datesub -d '2011/07/21 09:57:00'
+ datesub -d @2147483647
+ datesub -d @2147483648
+ datesub -d '2063/04/05 00:00:00'
+ for year in `seq 1970 1 2030`; do
+ datesub -d "${year}/01/01 00:00:00"
+ datesub -d "${year}/07/01 00:00:00"
+ done
+ for year in `seq 2000 25 2600`; do
+ datesub -d "$((${year} - 1))/12/31 23:59:59"
+ datesub -d "$((${year} + 0))/01/01 00:00:00"
+ datesub -d "$((${year} + 1))/01/01 00:00:00"
+ done
+)|sort -u
diff --git a/dev/clock_subr/t_clock_subr.c b/dev/clock_subr/t_clock_subr.c
new file mode 100644
index 000000000000..bb03c688bf79
--- /dev/null
+++ b/dev/clock_subr/t_clock_subr.c
@@ -0,0 +1,309 @@
+/* $NetBSD: t_clock_subr.c,v 1.3 2017/01/13 21:30:39 christos Exp $ */
+
+/*
+ * Copyright (c) 2016 Jonathan A. Kollasch
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__COPYRIGHT("@(#) Copyright (c) 2016\
+ Jonathan A. Kollasch. All rights reserved.");
+__RCSID("$NetBSD: t_clock_subr.c,v 1.3 2017/01/13 21:30:39 christos Exp $");
+
+#include <sys/types.h>
+#include <dev/clock_subr.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+#include "h_macros.h"
+
+#define FILL(ti,ye,mo,da,wd,ho,mi,se) \
+{ .time = (ti), .clock = { .dt_year = (ye), .dt_mon = (mo), .dt_day = (da), \
+ .dt_wday = (wd), .dt_hour = (ho), .dt_min = (mi), .dt_sec = (se), } }
+
+static struct clock_test {
+ time_t time;
+ struct clock_ymdhms clock;
+} const clock_tests[] = {
+ FILL( 0,1970, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 1970
+ FILL( 15638400,1970, 7, 1,3, 0, 0, 0), // Wed Jul 1 00:00:00 UTC 1970
+ FILL( 31536000,1971, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 1971
+ FILL( 47174400,1971, 7, 1,4, 0, 0, 0), // Thu Jul 1 00:00:00 UTC 1971
+ FILL( 63072000,1972, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 1972
+ FILL( 78796800,1972, 7, 1,6, 0, 0, 0), // Sat Jul 1 00:00:00 UTC 1972
+ FILL( 94694400,1973, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 1973
+ FILL( 110332800,1973, 7, 1,0, 0, 0, 0), // Sun Jul 1 00:00:00 UTC 1973
+ FILL( 126230400,1974, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 1974
+ FILL( 141868800,1974, 7, 1,1, 0, 0, 0), // Mon Jul 1 00:00:00 UTC 1974
+ FILL( 157766400,1975, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 1975
+ FILL( 173404800,1975, 7, 1,2, 0, 0, 0), // Tue Jul 1 00:00:00 UTC 1975
+ FILL( 189302400,1976, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 1976
+ FILL( 205027200,1976, 7, 1,4, 0, 0, 0), // Thu Jul 1 00:00:00 UTC 1976
+ FILL( 220924800,1977, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 1977
+ FILL( 236563200,1977, 7, 1,5, 0, 0, 0), // Fri Jul 1 00:00:00 UTC 1977
+ FILL( 252460800,1978, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 1978
+ FILL( 268099200,1978, 7, 1,6, 0, 0, 0), // Sat Jul 1 00:00:00 UTC 1978
+ FILL( 283996800,1979, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 1979
+ FILL( 299635200,1979, 7, 1,0, 0, 0, 0), // Sun Jul 1 00:00:00 UTC 1979
+ FILL( 315532800,1980, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 1980
+ FILL( 331257600,1980, 7, 1,2, 0, 0, 0), // Tue Jul 1 00:00:00 UTC 1980
+ FILL( 347155200,1981, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 1981
+ FILL( 355924803,1981, 4,12,0,12, 0, 3), // Sun Apr 12 12:00:03 UTC 1981
+ FILL( 362793600,1981, 7, 1,3, 0, 0, 0), // Wed Jul 1 00:00:00 UTC 1981
+ FILL( 378691200,1982, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 1982
+ FILL( 394329600,1982, 7, 1,4, 0, 0, 0), // Thu Jul 1 00:00:00 UTC 1982
+ FILL( 410227200,1983, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 1983
+ FILL( 425865600,1983, 7, 1,5, 0, 0, 0), // Fri Jul 1 00:00:00 UTC 1983
+ FILL( 441763200,1984, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 1984
+ FILL( 457488000,1984, 7, 1,0, 0, 0, 0), // Sun Jul 1 00:00:00 UTC 1984
+ FILL( 473385600,1985, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 1985
+ FILL( 489024000,1985, 7, 1,1, 0, 0, 0), // Mon Jul 1 00:00:00 UTC 1985
+ FILL( 504921600,1986, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 1986
+ FILL( 520560000,1986, 7, 1,2, 0, 0, 0), // Tue Jul 1 00:00:00 UTC 1986
+ FILL( 536457600,1987, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 1987
+ FILL( 552096000,1987, 7, 1,3, 0, 0, 0), // Wed Jul 1 00:00:00 UTC 1987
+ FILL( 567993600,1988, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 1988
+ FILL( 583718400,1988, 7, 1,5, 0, 0, 0), // Fri Jul 1 00:00:00 UTC 1988
+ FILL( 599616000,1989, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 1989
+ FILL( 615254400,1989, 7, 1,6, 0, 0, 0), // Sat Jul 1 00:00:00 UTC 1989
+ FILL( 631152000,1990, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 1990
+ FILL( 646790400,1990, 7, 1,0, 0, 0, 0), // Sun Jul 1 00:00:00 UTC 1990
+ FILL( 662688000,1991, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 1991
+ FILL( 678326400,1991, 7, 1,1, 0, 0, 0), // Mon Jul 1 00:00:00 UTC 1991
+ FILL( 694224000,1992, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 1992
+ FILL( 709948800,1992, 7, 1,3, 0, 0, 0), // Wed Jul 1 00:00:00 UTC 1992
+ FILL( 725846400,1993, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 1993
+ FILL( 741484800,1993, 7, 1,4, 0, 0, 0), // Thu Jul 1 00:00:00 UTC 1993
+ FILL( 757382400,1994, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 1994
+ FILL( 773020800,1994, 7, 1,5, 0, 0, 0), // Fri Jul 1 00:00:00 UTC 1994
+ FILL( 788918400,1995, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 1995
+ FILL( 804556800,1995, 7, 1,6, 0, 0, 0), // Sat Jul 1 00:00:00 UTC 1995
+ FILL( 820454400,1996, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 1996
+ FILL( 836179200,1996, 7, 1,1, 0, 0, 0), // Mon Jul 1 00:00:00 UTC 1996
+ FILL( 852076800,1997, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 1997
+ FILL( 867715200,1997, 7, 1,2, 0, 0, 0), // Tue Jul 1 00:00:00 UTC 1997
+ FILL( 883612800,1998, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 1998
+ FILL( 899251200,1998, 7, 1,3, 0, 0, 0), // Wed Jul 1 00:00:00 UTC 1998
+ FILL( 915148800,1999, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 1999
+ FILL( 930787200,1999, 7, 1,4, 0, 0, 0), // Thu Jul 1 00:00:00 UTC 1999
+ FILL( 946684799,1999,12,31,5,23,59,59), // Fri Dec 31 23:59:59 UTC 1999
+ FILL( 946684800,2000, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2000
+ FILL( 962409600,2000, 7, 1,6, 0, 0, 0), // Sat Jul 1 00:00:00 UTC 2000
+ FILL( 978307200,2001, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2001
+ FILL( 993945600,2001, 7, 1,0, 0, 0, 0), // Sun Jul 1 00:00:00 UTC 2001
+ FILL( 1009843200,2002, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2002
+ FILL( 1025481600,2002, 7, 1,1, 0, 0, 0), // Mon Jul 1 00:00:00 UTC 2002
+ FILL( 1041379200,2003, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2003
+ FILL( 1057017600,2003, 7, 1,2, 0, 0, 0), // Tue Jul 1 00:00:00 UTC 2003
+ FILL( 1072915200,2004, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2004
+ FILL( 1088640000,2004, 7, 1,4, 0, 0, 0), // Thu Jul 1 00:00:00 UTC 2004
+ FILL( 1104537600,2005, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2005
+ FILL( 1120176000,2005, 7, 1,5, 0, 0, 0), // Fri Jul 1 00:00:00 UTC 2005
+ FILL( 1136073600,2006, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 2006
+ FILL( 1151712000,2006, 7, 1,6, 0, 0, 0), // Sat Jul 1 00:00:00 UTC 2006
+ FILL( 1167609600,2007, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2007
+ FILL( 1183248000,2007, 7, 1,0, 0, 0, 0), // Sun Jul 1 00:00:00 UTC 2007
+ FILL( 1199145600,2008, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2008
+ FILL( 1214870400,2008, 7, 1,2, 0, 0, 0), // Tue Jul 1 00:00:00 UTC 2008
+ FILL( 1230768000,2009, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2009
+ FILL( 1246406400,2009, 7, 1,3, 0, 0, 0), // Wed Jul 1 00:00:00 UTC 2009
+ FILL( 1262304000,2010, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 2010
+ FILL( 1277942400,2010, 7, 1,4, 0, 0, 0), // Thu Jul 1 00:00:00 UTC 2010
+ FILL( 1293840000,2011, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2011
+ FILL( 1309478400,2011, 7, 1,5, 0, 0, 0), // Fri Jul 1 00:00:00 UTC 2011
+ FILL( 1311242220,2011, 7,21,4, 9,57, 0), // Thu Jul 21 09:57:00 UTC 2011
+ FILL( 1325376000,2012, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 2012
+ FILL( 1341100800,2012, 7, 1,0, 0, 0, 0), // Sun Jul 1 00:00:00 UTC 2012
+ FILL( 1356998400,2013, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2013
+ FILL( 1372636800,2013, 7, 1,1, 0, 0, 0), // Mon Jul 1 00:00:00 UTC 2013
+ FILL( 1388534400,2014, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2014
+ FILL( 1404172800,2014, 7, 1,2, 0, 0, 0), // Tue Jul 1 00:00:00 UTC 2014
+ FILL( 1420070400,2015, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2015
+ FILL( 1435708800,2015, 7, 1,3, 0, 0, 0), // Wed Jul 1 00:00:00 UTC 2015
+ FILL( 1451606400,2016, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 2016
+ FILL( 1467331200,2016, 7, 1,5, 0, 0, 0), // Fri Jul 1 00:00:00 UTC 2016
+ FILL( 1483228800,2017, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 2017
+ FILL( 1498867200,2017, 7, 1,6, 0, 0, 0), // Sat Jul 1 00:00:00 UTC 2017
+ FILL( 1514764800,2018, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2018
+ FILL( 1530403200,2018, 7, 1,0, 0, 0, 0), // Sun Jul 1 00:00:00 UTC 2018
+ FILL( 1546300800,2019, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2019
+ FILL( 1561939200,2019, 7, 1,1, 0, 0, 0), // Mon Jul 1 00:00:00 UTC 2019
+ FILL( 1577836800,2020, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2020
+ FILL( 1593561600,2020, 7, 1,3, 0, 0, 0), // Wed Jul 1 00:00:00 UTC 2020
+ FILL( 1609459200,2021, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 2021
+ FILL( 1625097600,2021, 7, 1,4, 0, 0, 0), // Thu Jul 1 00:00:00 UTC 2021
+ FILL( 1640995200,2022, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2022
+ FILL( 1656633600,2022, 7, 1,5, 0, 0, 0), // Fri Jul 1 00:00:00 UTC 2022
+ FILL( 1672531200,2023, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 2023
+ FILL( 1688169600,2023, 7, 1,6, 0, 0, 0), // Sat Jul 1 00:00:00 UTC 2023
+ FILL( 1704067200,2024, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2024
+ FILL( 1719792000,2024, 7, 1,1, 0, 0, 0), // Mon Jul 1 00:00:00 UTC 2024
+ FILL( 1735689599,2024,12,31,2,23,59,59), // Tue Dec 31 23:59:59 UTC 2024
+ FILL( 1735689600,2025, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2025
+ FILL( 1751328000,2025, 7, 1,2, 0, 0, 0), // Tue Jul 1 00:00:00 UTC 2025
+ FILL( 1767225600,2026, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2026
+ FILL( 1782864000,2026, 7, 1,3, 0, 0, 0), // Wed Jul 1 00:00:00 UTC 2026
+ FILL( 1798761600,2027, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 2027
+ FILL( 1814400000,2027, 7, 1,4, 0, 0, 0), // Thu Jul 1 00:00:00 UTC 2027
+ FILL( 1830297600,2028, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2028
+ FILL( 1846022400,2028, 7, 1,6, 0, 0, 0), // Sat Jul 1 00:00:00 UTC 2028
+ FILL( 1861920000,2029, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2029
+ FILL( 1877558400,2029, 7, 1,0, 0, 0, 0), // Sun Jul 1 00:00:00 UTC 2029
+ FILL( 1893456000,2030, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2030
+ FILL( 1909094400,2030, 7, 1,1, 0, 0, 0), // Mon Jul 1 00:00:00 UTC 2030
+ FILL( 2147483647,2038, 1,19,2, 3,14, 7), // Tue Jan 19 03:14:07 UTC 2038
+ FILL( 2147483648,2038, 1,19,2, 3,14, 8), // Tue Jan 19 03:14:08 UTC 2038
+ FILL( 2524607999,2049,12,31,5,23,59,59), // Fri Dec 31 23:59:59 UTC 2049
+ FILL( 2524608000,2050, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2050
+ FILL( 2556144000,2051, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 2051
+ FILL( 2942956800,2063, 4, 5,4, 0, 0, 0), // Thu Apr 5 00:00:00 UTC 2063
+ FILL( 3313526399,2074,12,31,1,23,59,59), // Mon Dec 31 23:59:59 UTC 2074
+ FILL( 3313526400,2075, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2075
+ FILL( 3345062400,2076, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2076
+ FILL( 4102444799,2099,12,31,4,23,59,59), // Thu Dec 31 23:59:59 UTC 2099
+ FILL( 4102444800,2100, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 2100
+ FILL( 4133980800,2101, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2101
+ FILL( 4891363199,2124,12,31,0,23,59,59), // Sun Dec 31 23:59:59 UTC 2124
+ FILL( 4891363200,2125, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2125
+ FILL( 4922899200,2126, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2126
+ FILL( 5680281599,2149,12,31,3,23,59,59), // Wed Dec 31 23:59:59 UTC 2149
+ FILL( 5680281600,2150, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2150
+ FILL( 5711817600,2151, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 2151
+ FILL( 6469199999,2174,12,31,6,23,59,59), // Sat Dec 31 23:59:59 UTC 2174
+ FILL( 6469200000,2175, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 2175
+ FILL( 6500736000,2176, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2176
+ FILL( 7258118399,2199,12,31,2,23,59,59), // Tue Dec 31 23:59:59 UTC 2199
+ FILL( 7258118400,2200, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2200
+ FILL( 7289654400,2201, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2201
+ FILL( 8047036799,2224,12,31,5,23,59,59), // Fri Dec 31 23:59:59 UTC 2224
+ FILL( 8047036800,2225, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2225
+ FILL( 8078572800,2226, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 2226
+ FILL( 8835955199,2249,12,31,1,23,59,59), // Mon Dec 31 23:59:59 UTC 2249
+ FILL( 8835955200,2250, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2250
+ FILL( 8867491200,2251, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2251
+ FILL( 9624873599,2274,12,31,4,23,59,59), // Thu Dec 31 23:59:59 UTC 2274
+ FILL( 9624873600,2275, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 2275
+ FILL( 9656409600,2276, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2276
+ FILL(10413791999,2299,12,31,0,23,59,59), // Sun Dec 31 23:59:59 UTC 2299
+ FILL(10413792000,2300, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2300
+ FILL(10445328000,2301, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2301
+ FILL(11202710399,2324,12,31,3,23,59,59), // Wed Dec 31 23:59:59 UTC 2324
+ FILL(11202710400,2325, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2325
+ FILL(11234246400,2326, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 2326
+ FILL(11991628799,2349,12,31,6,23,59,59), // Sat Dec 31 23:59:59 UTC 2349
+ FILL(11991628800,2350, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 2350
+ FILL(12023164800,2351, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2351
+ FILL(12780547199,2374,12,31,2,23,59,59), // Tue Dec 31 23:59:59 UTC 2374
+ FILL(12780547200,2375, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2375
+ FILL(12812083200,2376, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2376
+ FILL(13569465599,2399,12,31,5,23,59,59), // Fri Dec 31 23:59:59 UTC 2399
+ FILL(13569465600,2400, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2400
+ FILL(13601088000,2401, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2401
+ FILL(14358470399,2424,12,31,2,23,59,59), // Tue Dec 31 23:59:59 UTC 2424
+ FILL(14358470400,2425, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2425
+ FILL(14390006400,2426, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2426
+ FILL(15147388799,2449,12,31,5,23,59,59), // Fri Dec 31 23:59:59 UTC 2449
+ FILL(15147388800,2450, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2450
+ FILL(15178924800,2451, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 2451
+ FILL(15936307199,2474,12,31,1,23,59,59), // Mon Dec 31 23:59:59 UTC 2474
+ FILL(15936307200,2475, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2475
+ FILL(15967843200,2476, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2476
+ FILL(16725225599,2499,12,31,4,23,59,59), // Thu Dec 31 23:59:59 UTC 2499
+ FILL(16725225600,2500, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 2500
+ FILL(16756761600,2501, 1, 1,6, 0, 0, 0), // Sat Jan 1 00:00:00 UTC 2501
+ FILL(17514143999,2524,12,31,0,23,59,59), // Sun Dec 31 23:59:59 UTC 2524
+ FILL(17514144000,2525, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2525
+ FILL(17545680000,2526, 1, 1,2, 0, 0, 0), // Tue Jan 1 00:00:00 UTC 2526
+ FILL(18303062399,2549,12,31,3,23,59,59), // Wed Dec 31 23:59:59 UTC 2549
+ FILL(18303062400,2550, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2550
+ FILL(18334598400,2551, 1, 1,5, 0, 0, 0), // Fri Jan 1 00:00:00 UTC 2551
+ FILL(19091980799,2574,12,31,6,23,59,59), // Sat Dec 31 23:59:59 UTC 2574
+ FILL(19091980800,2575, 1, 1,0, 0, 0, 0), // Sun Jan 1 00:00:00 UTC 2575
+ FILL(19123516800,2576, 1, 1,1, 0, 0, 0), // Mon Jan 1 00:00:00 UTC 2576
+ FILL(19880899199,2599,12,31,2,23,59,59), // Tue Dec 31 23:59:59 UTC 2599
+ FILL(19880899200,2600, 1, 1,3, 0, 0, 0), // Wed Jan 1 00:00:00 UTC 2600
+ FILL(19912435200,2601, 1, 1,4, 0, 0, 0), // Thu Jan 1 00:00:00 UTC 2601
+};
+#undef FILL
+
+ATF_TC(ymdhms_to_secs);
+ATF_TC_HEAD(ymdhms_to_secs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "check clock_ymdhms_to_secs");
+}
+ATF_TC_BODY(ymdhms_to_secs, tc)
+{
+ time_t secs;
+ size_t i;
+
+ for (i = 0; i < __arraycount(clock_tests); i++) {
+ secs = clock_ymdhms_to_secs(__UNCONST(&clock_tests[i].clock));
+ ATF_CHECK_EQ_MSG(clock_tests[i].time, secs, "%jd != %jd",
+ (intmax_t)clock_tests[i].time, (intmax_t)secs);
+ }
+}
+
+ATF_TC(secs_to_ymdhms);
+ATF_TC_HEAD(secs_to_ymdhms, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "check clock_secs_to_ymdhms");
+}
+ATF_TC_BODY(secs_to_ymdhms, tc)
+{
+ struct clock_ymdhms ymdhms;
+ size_t i;
+
+#define CHECK_FIELD(f) \
+ ATF_CHECK_EQ_MSG(ymdhms.dt_##f, clock_tests[i].clock.dt_##f, \
+ "%jd != %jd for %jd", (intmax_t)ymdhms.dt_##f, \
+ (intmax_t)clock_tests[i].clock.dt_##f, \
+ (intmax_t)clock_tests[i].time)
+
+ for (i = 0; i < __arraycount(clock_tests); i++) {
+ clock_secs_to_ymdhms(clock_tests[i].time, &ymdhms);
+ CHECK_FIELD(year);
+ CHECK_FIELD(mon);
+ CHECK_FIELD(day);
+ CHECK_FIELD(wday);
+ CHECK_FIELD(hour);
+ CHECK_FIELD(min);
+ CHECK_FIELD(sec);
+ }
+#undef CHECK_FIELD
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, ymdhms_to_secs);
+ ATF_TP_ADD_TC(tp, secs_to_ymdhms);
+
+ return atf_no_error();
+}
diff --git a/kernel/arch/amd64/t_ptrace_wait.c b/kernel/arch/amd64/t_ptrace_wait.c
new file mode 100644
index 000000000000..5adbb0e94554
--- /dev/null
+++ b/kernel/arch/amd64/t_ptrace_wait.c
@@ -0,0 +1,1388 @@
+/* $NetBSD: t_ptrace_wait.c,v 1.9 2017/01/13 21:30:41 christos Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.9 2017/01/13 21:30:41 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <machine/reg.h>
+#include <x86/dbregs.h>
+#include <err.h>
+#include <errno.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "h_macros.h"
+
+#include "../../t_ptrace_wait.h"
+
+
+#if defined(HAVE_GPREGS)
+ATF_TC(regs1);
+ATF_TC_HEAD(regs1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_GETREGS and iterate over General Purpose registers");
+}
+
+ATF_TC_BODY(regs1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct reg r;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETREGS for the child process\n");
+ ATF_REQUIRE(ptrace(PT_GETREGS, child, &r, 0) != -1);
+
+ printf("RAX=%#" PRIxREGISTER "\n", r.regs[_REG_RAX]);
+ printf("RBX=%#" PRIxREGISTER "\n", r.regs[_REG_RBX]);
+ printf("RCX=%#" PRIxREGISTER "\n", r.regs[_REG_RCX]);
+ printf("RDX=%#" PRIxREGISTER "\n", r.regs[_REG_RDX]);
+
+ printf("RDI=%#" PRIxREGISTER "\n", r.regs[_REG_RDI]);
+ printf("RSI=%#" PRIxREGISTER "\n", r.regs[_REG_RSI]);
+
+ printf("GS=%#" PRIxREGISTER "\n", r.regs[_REG_GS]);
+ printf("FS=%#" PRIxREGISTER "\n", r.regs[_REG_FS]);
+ printf("ES=%#" PRIxREGISTER "\n", r.regs[_REG_ES]);
+ printf("DS=%#" PRIxREGISTER "\n", r.regs[_REG_DS]);
+ printf("CS=%#" PRIxREGISTER "\n", r.regs[_REG_CS]);
+ printf("SS=%#" PRIxREGISTER "\n", r.regs[_REG_SS]);
+
+ printf("RSP=%#" PRIxREGISTER "\n", r.regs[_REG_RSP]);
+ printf("RIP=%#" PRIxREGISTER "\n", r.regs[_REG_RIP]);
+
+ printf("RFLAGS=%#" PRIxREGISTER "\n", r.regs[_REG_RFLAGS]);
+
+ printf("R8=%#" PRIxREGISTER "\n", r.regs[_REG_R8]);
+ printf("R9=%#" PRIxREGISTER "\n", r.regs[_REG_R9]);
+ printf("R10=%#" PRIxREGISTER "\n", r.regs[_REG_R10]);
+ printf("R11=%#" PRIxREGISTER "\n", r.regs[_REG_R11]);
+ printf("R12=%#" PRIxREGISTER "\n", r.regs[_REG_R12]);
+ printf("R13=%#" PRIxREGISTER "\n", r.regs[_REG_R13]);
+ printf("R14=%#" PRIxREGISTER "\n", r.regs[_REG_R14]);
+ printf("R15=%#" PRIxREGISTER "\n", r.regs[_REG_R15]);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_count);
+ATF_TC_HEAD(watchpoint_count, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and assert four available watchpoints");
+}
+
+ATF_TC_BODY(watchpoint_count, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ int N;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETREGS for the child process\n");
+ ATF_REQUIRE((N = ptrace(PT_COUNT_WATCHPOINTS, child, NULL, 0)) != -1);
+ printf("Reported %d watchpoints\n", N);
+
+ ATF_REQUIRE_EQ_MSG(N, 4, "Expected 4 hw watchpoints - got %d", N);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_read);
+ATF_TC_HEAD(watchpoint_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and assert four available watchpoints");
+}
+
+ATF_TC_BODY(watchpoint_read, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ int i, N;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETREGS for the child process\n");
+ ATF_REQUIRE((N = ptrace(PT_COUNT_WATCHPOINTS, child, NULL, 0)) != -1);
+
+ ATF_REQUIRE_EQ_MSG(N, 4, "Expected 4 hw watchpoints - got %d", N);
+
+ for (i = 0; i < N; i++) {
+ printf("Before reading watchpoint %d\n", i);
+ pw.pw_index = i;
+ ATF_REQUIRE(ptrace(PT_READ_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+ }
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_write_unmodified);
+ATF_TC_HEAD(watchpoint_write_unmodified, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and assert functional write of "
+ "unmodified data");
+}
+
+ATF_TC_BODY(watchpoint_write_unmodified, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ int i, N;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETREGS for the child process\n");
+ ATF_REQUIRE((N = ptrace(PT_COUNT_WATCHPOINTS, child, NULL, 0)) != -1);
+
+ ATF_REQUIRE_EQ_MSG(N, 4, "Expected 4 hw watchpoints - got %d", N);
+
+ for (i = 0; i < N; i++) {
+ printf("Before reading watchpoint %d\n", i);
+ pw.pw_index = i;
+ ATF_REQUIRE(ptrace(PT_READ_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d (unmodified)\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len)
+ != -1);
+ }
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_code0);
+ATF_TC_HEAD(watchpoint_trap_code0, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test code trap with watchpoint 0");
+}
+
+ATF_TC_BODY(watchpoint_trap_code0, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 0;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("check_happy(%d)=%d\n", watchme, check_happy(watchme));
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_lwpid = 0;
+ pw.pw_md.md_address = (void *)check_happy;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_EXECUTION;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ pw.pw_md.md_address = NULL;
+ printf("Before writing watchpoint %d (disable it)\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_code1);
+ATF_TC_HEAD(watchpoint_trap_code1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test code trap with watchpoint 1");
+}
+
+ATF_TC_BODY(watchpoint_trap_code1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 1;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("check_happy(%d)=%d\n", watchme, check_happy(watchme));
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_lwpid = 0;
+ pw.pw_md.md_address = (void *)check_happy;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_EXECUTION;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ pw.pw_md.md_address = NULL;
+ printf("Before writing watchpoint %d (disable it)\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_code2);
+ATF_TC_HEAD(watchpoint_trap_code2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test code trap with watchpoint 2");
+}
+
+ATF_TC_BODY(watchpoint_trap_code2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 2;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("check_happy(%d)=%d\n", watchme, check_happy(watchme));
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_lwpid = 0;
+ pw.pw_md.md_address = (void *)check_happy;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_EXECUTION;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ pw.pw_md.md_address = NULL;
+ printf("Before writing watchpoint %d (disable it)\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_code3);
+ATF_TC_HEAD(watchpoint_trap_code3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test code trap with watchpoint 3");
+}
+
+ATF_TC_BODY(watchpoint_trap_code3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 3;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("check_happy(%d)=%d\n", watchme, check_happy(watchme));
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_lwpid = 0;
+ pw.pw_md.md_address = (void *)check_happy;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_EXECUTION;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ pw.pw_md.md_address = NULL;
+ printf("Before writing watchpoint %d (disable it)\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_data_write0);
+ATF_TC_HEAD(watchpoint_trap_data_write0, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test write trap with watchpoint 0");
+}
+
+ATF_TC_BODY(watchpoint_trap_data_write0, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 0;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ ++watchme;
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = 0;
+ pw.pw_md.md_address = &watchme;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_DATA_WRITE;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_data_write1);
+ATF_TC_HEAD(watchpoint_trap_data_write1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test write trap with watchpoint 1");
+}
+
+ATF_TC_BODY(watchpoint_trap_data_write1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 1;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ ++watchme;
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_md.md_address = &watchme;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_DATA_WRITE;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_data_write2);
+ATF_TC_HEAD(watchpoint_trap_data_write2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test write trap with watchpoint 2");
+}
+
+ATF_TC_BODY(watchpoint_trap_data_write2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 2;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ ++watchme;
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_md.md_address = &watchme;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_DATA_WRITE;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_data_write3);
+ATF_TC_HEAD(watchpoint_trap_data_write3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test write trap with watchpoint 3");
+}
+
+ATF_TC_BODY(watchpoint_trap_data_write3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 3;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ ++watchme;
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_md.md_address = &watchme;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_DATA_WRITE;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_data_rw0);
+ATF_TC_HEAD(watchpoint_trap_data_rw0, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test write trap with watchpoint 0");
+}
+
+ATF_TC_BODY(watchpoint_trap_data_rw0, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 0;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("watchme=%d\n", watchme);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_md.md_address = &watchme;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_DATA_READWRITE;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_data_rw1);
+ATF_TC_HEAD(watchpoint_trap_data_rw1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test write trap with watchpoint 1");
+}
+
+ATF_TC_BODY(watchpoint_trap_data_rw1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 1;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("watchme=%d\n", watchme);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_md.md_address = &watchme;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_DATA_READWRITE;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_data_rw2);
+ATF_TC_HEAD(watchpoint_trap_data_rw2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test write trap with watchpoint 2");
+}
+
+ATF_TC_BODY(watchpoint_trap_data_rw2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 2;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("watchme=%d\n", watchme);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_md.md_address = &watchme;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_DATA_READWRITE;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+ATF_TC(watchpoint_trap_data_rw3);
+ATF_TC_HEAD(watchpoint_trap_data_rw3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_COUNT_WATCHPOINTS and test write trap with watchpoint 3");
+}
+
+ATF_TC_BODY(watchpoint_trap_data_rw3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ const int i = 3;
+ struct ptrace_watchpoint pw;
+ int len = sizeof(pw);
+ int watchme = 1234;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("watchme=%d\n", watchme);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Preparing code watchpoint trap %d\n", i);
+
+ pw.pw_index = i;
+ pw.pw_md.md_address = &watchme;
+ pw.pw_md.md_condition = X86_HW_WATCHPOINT_DR7_CONDITION_DATA_READWRITE;
+ pw.pw_md.md_length = X86_HW_WATCHPOINT_DR7_LENGTH_BYTE;
+
+ printf("struct ptrace {\n");
+ printf("\t.pw_index=%d\n", pw.pw_index);
+ printf("\t.pw_lwpid=%d\n", pw.pw_lwpid);
+ printf("\t.pw_md.md_address=%p\n", pw.pw_md.md_address);
+ printf("\t.pw_md.md_condition=%#x\n", pw.pw_md.md_condition);
+ printf("\t.pw_md.md_length=%#x\n", pw.pw_md.md_length);
+ printf("}\n");
+
+ printf("Before writing watchpoint %d\n", i);
+ ATF_REQUIRE(ptrace(PT_WRITE_WATCHPOINT, child, &pw, len) != -1);
+
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+ATF_TP_ADD_TCS(tp)
+{
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ ATF_TP_ADD_TC_HAVE_GPREGS(tp, regs1);
+
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_count);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_read);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_write_unmodified);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_code0);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_code1);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_code2);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_code3);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_data_write0);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_data_write1);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_data_write2);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_data_write3);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_data_rw0);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_data_rw1);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_data_rw2);
+ ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(tp, watchpoint_trap_data_rw3);
+
+ return atf_no_error();
+}
diff --git a/kernel/arch/amd64/t_ptrace_wait3.c b/kernel/arch/amd64/t_ptrace_wait3.c
new file mode 100644
index 000000000000..c5dfe7358738
--- /dev/null
+++ b/kernel/arch/amd64/t_ptrace_wait3.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_wait3.c,v 1.1 2016/12/02 05:54:15 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_WAIT3
+#include "t_ptrace_wait.c"
diff --git a/kernel/arch/amd64/t_ptrace_wait4.c b/kernel/arch/amd64/t_ptrace_wait4.c
new file mode 100644
index 000000000000..7e1fed95ee62
--- /dev/null
+++ b/kernel/arch/amd64/t_ptrace_wait4.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_wait4.c,v 1.1 2016/12/02 05:54:15 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_WAIT4
+#include "t_ptrace_wait.c"
diff --git a/kernel/arch/amd64/t_ptrace_wait6.c b/kernel/arch/amd64/t_ptrace_wait6.c
new file mode 100644
index 000000000000..601efe3f3d62
--- /dev/null
+++ b/kernel/arch/amd64/t_ptrace_wait6.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_wait6.c,v 1.1 2016/12/02 05:54:15 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_WAIT6
+#include "t_ptrace_wait.c"
diff --git a/kernel/arch/amd64/t_ptrace_waitid.c b/kernel/arch/amd64/t_ptrace_waitid.c
new file mode 100644
index 000000000000..5ec17a9b8d24
--- /dev/null
+++ b/kernel/arch/amd64/t_ptrace_waitid.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_waitid.c,v 1.1 2016/12/02 05:54:15 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_WAITID
+#include "t_ptrace_wait.c"
diff --git a/kernel/arch/amd64/t_ptrace_waitpid.c b/kernel/arch/amd64/t_ptrace_waitpid.c
new file mode 100644
index 000000000000..78b341c111f3
--- /dev/null
+++ b/kernel/arch/amd64/t_ptrace_waitpid.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_waitpid.c,v 1.1 2016/12/02 05:54:15 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_WAITPID
+#include "t_ptrace_wait.c"
diff --git a/kernel/arch/i386/t_ptrace_wait.c b/kernel/arch/i386/t_ptrace_wait.c
new file mode 100644
index 000000000000..698573bb0985
--- /dev/null
+++ b/kernel/arch/i386/t_ptrace_wait.c
@@ -0,0 +1,141 @@
+/* $NetBSD: t_ptrace_wait.c,v 1.2 2017/01/13 21:30:41 christos Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.2 2017/01/13 21:30:41 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <machine/reg.h>
+#include <err.h>
+#include <errno.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "h_macros.h"
+
+#include "../../t_ptrace_wait.h"
+
+
+#if defined(HAVE_GPREGS)
+ATF_TC(regs1);
+ATF_TC_HEAD(regs1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Call PT_GETREGS and iterate over General Purpose registers");
+}
+
+ATF_TC_BODY(regs1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct reg r;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETREGS for the child process\n");
+ ATF_REQUIRE(ptrace(PT_GETREGS, child, &r, 0) != -1);
+
+ printf("EAX=%#" PRIxREGISTER "\n", r.r_eax);
+ printf("EBX=%#" PRIxREGISTER "\n", r.r_ebx);
+ printf("ECX=%#" PRIxREGISTER "\n", r.r_ecx);
+ printf("EDX=%#" PRIxREGISTER "\n", r.r_edx);
+
+ printf("ESP=%#" PRIxREGISTER "\n", r.r_esp);
+ printf("EBP=%#" PRIxREGISTER "\n", r.r_ebp);
+
+ printf("ESI=%#" PRIxREGISTER "\n", r.r_esi);
+ printf("EDI=%#" PRIxREGISTER "\n", r.r_edi);
+
+ printf("EIP=%#" PRIxREGISTER "\n", r.r_eip);
+
+ printf("EFLAGS=%#" PRIxREGISTER "\n", r.r_eflags);
+
+ printf("CS=%#" PRIxREGISTER "\n", r.r_cs);
+ printf("SS=%#" PRIxREGISTER "\n", r.r_ss);
+ printf("DS=%#" PRIxREGISTER "\n", r.r_ds);
+ printf("ES=%#" PRIxREGISTER "\n", r.r_es);
+ printf("FS=%#" PRIxREGISTER "\n", r.r_fs);
+ printf("GS=%#" PRIxREGISTER "\n", r.r_gs);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+ATF_TP_ADD_TCS(tp)
+{
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ ATF_TP_ADD_TC_HAVE_GPREGS(tp, regs1);
+
+ return atf_no_error();
+}
diff --git a/kernel/arch/i386/t_ptrace_wait3.c b/kernel/arch/i386/t_ptrace_wait3.c
new file mode 100644
index 000000000000..56dda8e6978d
--- /dev/null
+++ b/kernel/arch/i386/t_ptrace_wait3.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_wait3.c,v 1.1 2016/12/13 18:00:10 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_WAIT3
+#include "t_ptrace_wait.c"
diff --git a/kernel/arch/i386/t_ptrace_wait4.c b/kernel/arch/i386/t_ptrace_wait4.c
new file mode 100644
index 000000000000..5fbdb53503b9
--- /dev/null
+++ b/kernel/arch/i386/t_ptrace_wait4.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_wait4.c,v 1.1 2016/12/13 18:00:10 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_WAIT4
+#include "t_ptrace_wait.c"
diff --git a/kernel/arch/i386/t_ptrace_wait6.c b/kernel/arch/i386/t_ptrace_wait6.c
new file mode 100644
index 000000000000..117c844123c9
--- /dev/null
+++ b/kernel/arch/i386/t_ptrace_wait6.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_wait6.c,v 1.1 2016/12/13 18:00:10 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_WAIT6
+#include "t_ptrace_wait.c"
diff --git a/kernel/arch/i386/t_ptrace_waitid.c b/kernel/arch/i386/t_ptrace_waitid.c
new file mode 100644
index 000000000000..274e8bd9f19c
--- /dev/null
+++ b/kernel/arch/i386/t_ptrace_waitid.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_waitid.c,v 1.1 2016/12/13 18:00:10 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_WAITID
+#include "t_ptrace_wait.c"
diff --git a/kernel/arch/i386/t_ptrace_waitpid.c b/kernel/arch/i386/t_ptrace_waitpid.c
new file mode 100644
index 000000000000..2fe5c570f9f7
--- /dev/null
+++ b/kernel/arch/i386/t_ptrace_waitpid.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_waitpid.c,v 1.1 2016/12/13 18:00:10 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_WAITPID
+#include "t_ptrace_wait.c"
diff --git a/kernel/t_ptrace_wait.c b/kernel/t_ptrace_wait.c
index d8935904c516..b1b4d1bef2c2 100644
--- a/kernel/t_ptrace_wait.c
+++ b/kernel/t_ptrace_wait.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_wait.c,v 1.57 2017/01/13 23:22:12 kamil Exp $ */
+/* $NetBSD: t_ptrace_wait.c,v 1.58 2017/01/14 04:37:55 kamil Exp $ */
/*-
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_wait.c,v 1.57 2017/01/13 23:22:12 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.58 2017/01/14 04:37:55 kamil Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -1072,6 +1072,118 @@ ATF_TC_BODY(eventmask2, tc)
TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
}
+ATF_TC(eventmask3);
+ATF_TC_HEAD(eventmask3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that PTRACE_VFORK in EVENT_MASK is preserved");
+}
+
+ATF_TC_BODY(eventmask3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_event_t set_event, get_event;
+ const int len = sizeof(ptrace_event_t);
+
+ atf_tc_expect_fail("PR kern/51630");
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ set_event.pe_set_event = PTRACE_VFORK;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
+ ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
+ ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(eventmask4);
+ATF_TC_HEAD(eventmask4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that PTRACE_VFORK_DONE in EVENT_MASK is preserved");
+}
+
+ATF_TC_BODY(eventmask4, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_event_t set_event, get_event;
+ const int len = sizeof(ptrace_event_t);
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ set_event.pe_set_event = PTRACE_VFORK_DONE;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
+ ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
+ ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
#if defined(TWAIT_HAVE_PID)
ATF_TC(fork1);
ATF_TC_HEAD(fork1, tc)
@@ -5193,6 +5305,8 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, eventmask1);
ATF_TP_ADD_TC(tp, eventmask2);
+ ATF_TP_ADD_TC(tp, eventmask3);
+ ATF_TP_ADD_TC(tp, eventmask4);
ATF_TP_ADD_TC_HAVE_PID(tp, fork1);
ATF_TP_ADD_TC(tp, fork2);
diff --git a/lib/libc/gen/exect/t_exect.c b/lib/libc/gen/exect/t_exect.c
new file mode 100644
index 000000000000..4c85e4b2db4b
--- /dev/null
+++ b/lib/libc/gen/exect/t_exect.c
@@ -0,0 +1,90 @@
+/* $NetBSD: t_exect.c,v 1.6 2016/12/12 10:34:55 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <atf-c.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+
+ATF_TC(t_exect_null);
+
+ATF_TC_HEAD(t_exect_null, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Tests an empty exect(2) executing");
+}
+
+static volatile sig_atomic_t caught = 0;
+
+static void
+sigtrap_handler(int sig, siginfo_t *info, void *ctx)
+{
+ ATF_REQUIRE_EQ(sig, SIGTRAP);
+ ATF_REQUIRE_EQ(info->si_code, TRAP_TRACE);
+
+ ++caught;
+}
+
+ATF_TC_BODY(t_exect_null, tc)
+{
+ struct sigaction act;
+
+ /*
+ * Currently exect(3) is misdesigned -- see PR port-amd64/51700 and it
+ * needs to be redone from scratch.
+ *
+ * This test affects amd64 releng machines causing tests to hang or
+ * fail. As there is little point to test interface that is still not,
+ * designed and implemented and is breaking tests - skip it
+ * unconditionally for all ports.
+ */
+ /* Prevent static analysis from requiring t_exec_null to be __dead. */
+ if (!caught)
+ atf_tc_skip("exect(3) misdesigned and hangs - PR port-amd64/51700");
+
+ ATF_REQUIRE(sigemptyset(&act.sa_mask) == 0);
+ act.sa_sigaction = sigtrap_handler;
+ act.sa_flags = SA_SIGINFO;
+
+ ATF_REQUIRE(sigaction(SIGTRAP, &act, 0) == 0);
+
+ ATF_REQUIRE_ERRNO(EFAULT, exect(NULL, NULL, NULL) == -1);
+
+ ATF_REQUIRE_EQ_MSG(caught, 1, "expected caught (1) != received (%d)",
+ (int)caught);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, t_exect_null);
+
+ return atf_no_error();
+}
diff --git a/lib/libpthread_dbg/h_common.h b/lib/libpthread_dbg/h_common.h
new file mode 100644
index 000000000000..0a02b963d436
--- /dev/null
+++ b/lib/libpthread_dbg/h_common.h
@@ -0,0 +1,128 @@
+/* $NetBSD: h_common.h,v 1.2 2016/11/19 02:30:54 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef H_COMMON_H
+#define H_COMMON_H
+
+#include <sys/cdefs.h>
+#include <dlfcn.h>
+#include <pthread_dbg.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+#define PTHREAD_REQUIRE(x) \
+ do { \
+ int ret = (x); \
+ ATF_REQUIRE_MSG(ret == 0, "%s: %s", #x, strerror(ret)); \
+ } while (0)
+
+#define PTHREAD_REQUIRE_STATUS(x, v) \
+ do { \
+ int ret = (x); \
+ ATF_REQUIRE_MSG(ret == (v), "%s: %s", #x, strerror(ret)); \
+ } while (0)
+
+static int __used
+dummy_proc_read(void *arg, caddr_t addr, void *buf, size_t size)
+{
+ return TD_ERR_ERR;
+}
+
+static int __used
+dummy_proc_write(void *arg, caddr_t addr, void *buf, size_t size)
+{
+ return TD_ERR_ERR;
+}
+
+static int __used
+dummy_proc_lookup(void *arg, const char *sym, caddr_t *addr)
+{
+ return TD_ERR_ERR;
+}
+
+static int __used
+dummy_proc_regsize(void *arg, int regset, size_t *size)
+{
+ return TD_ERR_ERR;
+}
+
+static int __used
+dummy_proc_getregs(void *arg, int regset, int lwp, void *buf)
+{
+ return TD_ERR_ERR;
+}
+
+static int __used
+dummy_proc_setregs(void *arg, int regset, int lwp, void *buf)
+{
+ return TD_ERR_ERR;
+}
+
+/* Minimalistic basic implementation */
+
+static int __used
+basic_proc_read(void *arg, caddr_t addr, void *buf, size_t size)
+{
+ memcpy(buf, addr, size);
+
+ return TD_ERR_OK;
+}
+
+static int __used
+basic_proc_write(void *arg, caddr_t addr, void *buf, size_t size)
+{
+ memcpy(addr, buf, size);
+
+ return TD_ERR_OK;
+}
+
+static int __used
+basic_proc_lookup(void *arg, const char *sym, caddr_t *addr)
+{
+ void *handle;
+ void *symbol;
+
+ ATF_REQUIRE_MSG((handle = dlopen(NULL, RTLD_LOCAL | RTLD_LAZY))
+ != NULL, "dlopen(3) failed: %s", dlerror());
+
+ symbol = dlsym(handle, sym);
+
+ ATF_REQUIRE_MSG(dlclose(handle) == 0, "dlclose(3) failed: %s",
+ dlerror());
+
+ if (!symbol)
+ return TD_ERR_NOSYM;
+
+ *addr = (caddr_t)(uintptr_t)symbol;
+
+ return TD_ERR_OK;
+}
+
+#endif // H_COMMON_H
diff --git a/lib/libpthread_dbg/t_dummy.c b/lib/libpthread_dbg/t_dummy.c
new file mode 100644
index 000000000000..367443cd0351
--- /dev/null
+++ b/lib/libpthread_dbg/t_dummy.c
@@ -0,0 +1,131 @@
+/* $NetBSD: t_dummy.c,v 1.6 2016/11/19 15:13:46 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_dummy.c,v 1.6 2016/11/19 15:13:46 kamil Exp $");
+
+#include "h_common.h"
+#include <pthread_dbg.h>
+#include <stdio.h>
+
+#include <atf-c.h>
+
+
+ATF_TC(dummy1);
+ATF_TC_HEAD(dummy1, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that dummy lookup functions stop td_open() with failure");
+}
+
+ATF_TC_BODY(dummy1, tc)
+{
+
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+
+ dummy_callbacks.proc_read = dummy_proc_read;
+ dummy_callbacks.proc_write = dummy_proc_write;
+ dummy_callbacks.proc_lookup = dummy_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_ERR);
+}
+
+ATF_TC(dummy2);
+ATF_TC_HEAD(dummy2, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that td_open() for basic proc_{read,write,lookup} works");
+}
+
+ATF_TC_BODY(dummy2, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+ printf("Calling td_open(3)\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_OK);
+
+ printf("Calling td_close(3)\n");
+ ATF_REQUIRE(td_close(main_ta) == TD_ERR_OK);
+}
+
+ATF_TC(dummy3);
+ATF_TC_HEAD(dummy3, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that calling twice td_open() for the same process fails");
+}
+
+ATF_TC_BODY(dummy3, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta1;
+ td_proc_t *main_ta2;
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+ printf("Calling td_open(3) for the first time - expecting success\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta1) == TD_ERR_OK);
+
+ printf("Calling td_open(3) for the first time - expecting in-use\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta2) ==
+ TD_ERR_INUSE);
+
+ printf("Calling td_close(3) for the first successful call\n");
+ ATF_REQUIRE(td_close(main_ta1) == TD_ERR_OK);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, dummy1);
+ ATF_TP_ADD_TC(tp, dummy2);
+ ATF_TP_ADD_TC(tp, dummy3);
+
+ return atf_no_error();
+}
diff --git a/lib/libpthread_dbg/t_threads.c b/lib/libpthread_dbg/t_threads.c
new file mode 100644
index 000000000000..f22bbc9c0563
--- /dev/null
+++ b/lib/libpthread_dbg/t_threads.c
@@ -0,0 +1,719 @@
+/* $NetBSD: t_threads.c,v 1.9 2017/01/13 05:18:22 christos Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_threads.c,v 1.9 2017/01/13 05:18:22 christos Exp $");
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <pthread_dbg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "h_common.h"
+
+#define MAX_THREADS (size_t)10
+
+ATF_TC(threads1);
+ATF_TC_HEAD(threads1, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that td_thr_iter() call without extra logic works");
+}
+
+static volatile int exiting1;
+
+static void *
+busyFunction1(void *arg)
+{
+
+ while (exiting1 == 0)
+ usleep(50000);
+
+ return NULL;
+}
+
+static int
+iterateThreads1(td_thread_t *thread, void *arg)
+{
+
+ return TD_ERR_OK;
+}
+
+ATF_TC_BODY(threads1, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+ size_t i;
+ pthread_t threads[MAX_THREADS];
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ printf("Creating thread %zu\n", i);
+ PTHREAD_REQUIRE
+ (pthread_create(&threads[i], NULL, busyFunction1, NULL));
+ }
+
+ printf("Calling td_open(3)\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE(td_thr_iter(main_ta, iterateThreads1, NULL) == TD_ERR_OK);
+
+ exiting1 = 1;
+
+ printf("Calling td_close(3)\n");
+ ATF_REQUIRE(td_close(main_ta) == TD_ERR_OK);
+}
+
+ATF_TC(threads2);
+ATF_TC_HEAD(threads2, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that td_thr_iter() call is executed for each thread once");
+}
+
+static volatile int exiting2;
+
+static void *
+busyFunction2(void *arg)
+{
+
+ while (exiting2 == 0)
+ usleep(50000);
+
+ return NULL;
+}
+
+static int
+iterateThreads2(td_thread_t *thread, void *arg)
+{
+ int *counter = (int *)arg;
+
+ ++(*counter);
+
+ return TD_ERR_OK;
+}
+
+ATF_TC_BODY(threads2, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+ size_t i;
+ pthread_t threads[MAX_THREADS];
+ int count = 0;
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ printf("Creating thread %zu\n", i);
+ PTHREAD_REQUIRE
+ (pthread_create(&threads[i], NULL, busyFunction2, NULL));
+ }
+
+ printf("Calling td_open(3)\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE(td_thr_iter(main_ta, iterateThreads2, &count) == TD_ERR_OK);
+
+ exiting2 = 1;
+
+ printf("Calling td_close(3)\n");
+ ATF_REQUIRE(td_close(main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE_EQ_MSG(count, MAX_THREADS + 1,
+ "counted threads (%d) != expected threads (%zu)",
+ count, MAX_THREADS + 1);
+}
+
+ATF_TC(threads3);
+ATF_TC_HEAD(threads3, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that for each td_thr_iter() call td_thr_info() is valid");
+}
+
+static volatile int exiting3;
+
+static void *
+busyFunction3(void *arg)
+{
+
+ while (exiting3 == 0)
+ usleep(50000);
+
+ return NULL;
+}
+
+static int
+iterateThreads3(td_thread_t *thread, void *arg)
+{
+ int *counter = (int *)arg;
+ td_thread_info_t info;
+
+ ATF_REQUIRE(td_thr_info(thread, &info) == TD_ERR_OK);
+
+ ++(*counter);
+
+ return TD_ERR_OK;
+}
+
+ATF_TC_BODY(threads3, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+ size_t i;
+ pthread_t threads[MAX_THREADS];
+ int count = 0;
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ printf("Creating thread %zu\n", i);
+ PTHREAD_REQUIRE
+ (pthread_create(&threads[i], NULL, busyFunction3, NULL));
+ }
+
+ printf("Calling td_open(3)\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE(td_thr_iter(main_ta, iterateThreads3, &count) == TD_ERR_OK);
+
+ exiting3 = 1;
+
+ printf("Calling td_close(3)\n");
+ ATF_REQUIRE(td_close(main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE_EQ_MSG(count, MAX_THREADS + 1,
+ "counted threads (%d) != expected threads (%zu)",
+ count, MAX_THREADS + 1);
+}
+
+ATF_TC(threads4);
+ATF_TC_HEAD(threads4, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that for each td_thr_iter() call td_thr_getname() is "
+ "valid");
+}
+
+static volatile int exiting4;
+
+static void *
+busyFunction4(void *arg)
+{
+
+ while (exiting4 == 0)
+ usleep(50000);
+
+ return NULL;
+}
+
+static int
+iterateThreads4(td_thread_t *thread, void *arg)
+{
+ int *counter = (int *)arg;
+ char name[PTHREAD_MAX_NAMELEN_NP];
+
+ ATF_REQUIRE(td_thr_getname(thread, name, sizeof(name)) == TD_ERR_OK);
+
+ printf("Thread name: %s\n", name);
+
+ ++(*counter);
+
+ return TD_ERR_OK;
+}
+
+ATF_TC_BODY(threads4, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+ size_t i;
+ pthread_t threads[MAX_THREADS];
+ int count = 0;
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ printf("Creating thread %zu\n", i);
+ PTHREAD_REQUIRE
+ (pthread_create(&threads[i], NULL, busyFunction4, NULL));
+ }
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ PTHREAD_REQUIRE
+ (pthread_setname_np(threads[i], "test_%d", (void*)i));
+ }
+
+ printf("Calling td_open(3)\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE(td_thr_iter(main_ta, iterateThreads4, &count) == TD_ERR_OK);
+
+ exiting4 = 1;
+
+ printf("Calling td_close(3)\n");
+ ATF_REQUIRE(td_close(main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE_EQ_MSG(count, MAX_THREADS + 1,
+ "counted threads (%d) != expected threads (%zu)",
+ count, MAX_THREADS + 1);
+}
+
+ATF_TC(threads5);
+ATF_TC_HEAD(threads5, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that td_thr_getname() handles shorter buffer parameter "
+ "and the result is properly truncated");
+}
+
+static volatile int exiting5;
+
+static void *
+busyFunction5(void *arg)
+{
+
+ while (exiting5 == 0)
+ usleep(50000);
+
+ return NULL;
+}
+
+static int
+iterateThreads5(td_thread_t *thread, void *arg)
+{
+ int *counter = (int *)arg;
+ /* Arbitrarily short string buffer */
+ char name[3];
+
+ ATF_REQUIRE(td_thr_getname(thread, name, sizeof(name)) == TD_ERR_OK);
+
+ printf("Thread name: %s\n", name);
+
+ /* strlen(3) does not count including a '\0' character */
+ ATF_REQUIRE(strlen(name) < sizeof(name));
+
+ ++(*counter);
+
+ return TD_ERR_OK;
+}
+
+ATF_TC_BODY(threads5, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+ size_t i;
+ pthread_t threads[MAX_THREADS];
+ int count = 0;
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ printf("Creating thread %zu\n", i);
+ PTHREAD_REQUIRE
+ (pthread_create(&threads[i], NULL, busyFunction5, NULL));
+ }
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ PTHREAD_REQUIRE
+ (pthread_setname_np(threads[i], "test_%d", (void*)i));
+ }
+
+ printf("Calling td_open(3)\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE(td_thr_iter(main_ta, iterateThreads5, &count) == TD_ERR_OK);
+
+ exiting5 = 1;
+
+ printf("Calling td_close(3)\n");
+ ATF_REQUIRE(td_close(main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE_EQ_MSG(count, MAX_THREADS + 1,
+ "counted threads (%d) != expected threads (%zu)",
+ count, MAX_THREADS + 1);
+}
+
+ATF_TC(threads6);
+ATF_TC_HEAD(threads6, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that pthread_t can be translated with td_map_pth2thr() "
+ "to td_thread_t -- and assert earlier that td_thr_iter() call is "
+ "valid");
+}
+
+static volatile int exiting6;
+
+static void *
+busyFunction6(void *arg)
+{
+
+ while (exiting6 == 0)
+ usleep(50000);
+
+ return NULL;
+}
+
+static int
+iterateThreads6(td_thread_t *thread, void *arg)
+{
+ int *counter = (int *)arg;
+
+ ++(*counter);
+
+ return TD_ERR_OK;
+}
+
+ATF_TC_BODY(threads6, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+ size_t i;
+ pthread_t threads[MAX_THREADS];
+ int count = 0;
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ printf("Creating thread %zu\n", i);
+ PTHREAD_REQUIRE
+ (pthread_create(&threads[i], NULL, busyFunction6, NULL));
+ }
+
+ printf("Calling td_open(3)\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE(td_thr_iter(main_ta, iterateThreads6, &count) == TD_ERR_OK);
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ td_thread_t *td_thread;
+ ATF_REQUIRE(td_map_pth2thr(main_ta, threads[i], &td_thread)
+ == TD_ERR_OK);
+ }
+
+ exiting6 = 1;
+
+ printf("Calling td_close(3)\n");
+ ATF_REQUIRE(td_close(main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE_EQ_MSG(count, MAX_THREADS + 1,
+ "counted threads (%d) != expected threads (%zu)",
+ count, MAX_THREADS + 1);
+}
+
+ATF_TC(threads7);
+ATF_TC_HEAD(threads7, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that pthread_t can be translated with td_map_pth2thr() "
+ "to td_thread_t -- and assert later that td_thr_iter() call is "
+ "valid");
+}
+
+static volatile int exiting7;
+
+static void *
+busyFunction7(void *arg)
+{
+
+ while (exiting7 == 0)
+ usleep(50000);
+
+ return NULL;
+}
+
+static int
+iterateThreads7(td_thread_t *thread, void *arg)
+{
+ int *counter = (int *)arg;
+
+ ++(*counter);
+
+ return TD_ERR_OK;
+}
+
+ATF_TC_BODY(threads7, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+ size_t i;
+ pthread_t threads[MAX_THREADS];
+ int count = 0;
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ printf("Creating thread %zu\n", i);
+ PTHREAD_REQUIRE
+ (pthread_create(&threads[i], NULL, busyFunction7, NULL));
+ }
+
+ printf("Calling td_open(3)\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_OK);
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ td_thread_t *td_thread;
+ ATF_REQUIRE(td_map_pth2thr(main_ta, threads[i], &td_thread)
+ == TD_ERR_OK);
+ }
+
+ ATF_REQUIRE(td_thr_iter(main_ta, iterateThreads7, &count) == TD_ERR_OK);
+
+ exiting7 = 1;
+
+ printf("Calling td_close(3)\n");
+ ATF_REQUIRE(td_close(main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE_EQ_MSG(count, MAX_THREADS + 1,
+ "counted threads (%d) != expected threads (%zu)",
+ count, MAX_THREADS + 1);
+}
+
+ATF_TC(threads8);
+ATF_TC_HEAD(threads8, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that pthread_t can be translated with td_map_pth2thr() "
+ "to td_thread_t -- compare thread's name of pthread_t and "
+ "td_thread_t");
+}
+
+static volatile int exiting8;
+
+static void *
+busyFunction8(void *arg)
+{
+
+ while (exiting8 == 0)
+ usleep(50000);
+
+ return NULL;
+}
+
+static int
+iterateThreads8(td_thread_t *thread, void *arg)
+{
+ int *counter = (int *)arg;
+
+ ++(*counter);
+
+ return TD_ERR_OK;
+}
+
+ATF_TC_BODY(threads8, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+ size_t i;
+ pthread_t threads[MAX_THREADS];
+ int count = 0;
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ printf("Creating thread %zu\n", i);
+ PTHREAD_REQUIRE
+ (pthread_create(&threads[i], NULL, busyFunction8, NULL));
+ }
+
+ printf("Calling td_open(3)\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE(td_thr_iter(main_ta, iterateThreads8, &count) == TD_ERR_OK);
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ td_thread_t *td_thread;
+ char td_threadname[PTHREAD_MAX_NAMELEN_NP];
+ char pth_threadname[PTHREAD_MAX_NAMELEN_NP];
+ ATF_REQUIRE(td_map_pth2thr(main_ta, threads[i], &td_thread)
+ == TD_ERR_OK);
+ ATF_REQUIRE(td_thr_getname(td_thread, td_threadname,
+ sizeof(td_threadname)) == TD_ERR_OK);
+ PTHREAD_REQUIRE(pthread_getname_np(threads[i], pth_threadname,
+ sizeof(pth_threadname)));
+ ATF_REQUIRE(strcmp(td_threadname, pth_threadname) == 0);
+ }
+
+ exiting8 = 1;
+
+ printf("Calling td_close(3)\n");
+ ATF_REQUIRE(td_close(main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE_EQ_MSG(count, MAX_THREADS + 1,
+ "counted threads (%d) != expected threads (%zu)",
+ count, MAX_THREADS + 1);
+}
+
+ATF_TC(threads9);
+ATF_TC_HEAD(threads9, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Asserts that pthread_t can be translated with td_map_pth2thr() "
+ "to td_thread_t -- assert that thread is in the TD_STATE_RUNNING "
+ "state");
+}
+
+static volatile int exiting9;
+
+static void *
+busyFunction9(void *arg)
+{
+
+ while (exiting9 == 0)
+ usleep(50000);
+
+ return NULL;
+}
+
+static int
+iterateThreads9(td_thread_t *thread, void *arg)
+{
+ int *counter = (int *)arg;
+
+ ++(*counter);
+
+ return TD_ERR_OK;
+}
+
+ATF_TC_BODY(threads9, tc)
+{
+ struct td_proc_callbacks_t dummy_callbacks;
+ td_proc_t *main_ta;
+ size_t i;
+ pthread_t threads[MAX_THREADS];
+ int count = 0;
+
+ dummy_callbacks.proc_read = basic_proc_read;
+ dummy_callbacks.proc_write = basic_proc_write;
+ dummy_callbacks.proc_lookup = basic_proc_lookup;
+ dummy_callbacks.proc_regsize = dummy_proc_regsize;
+ dummy_callbacks.proc_getregs = dummy_proc_getregs;
+ dummy_callbacks.proc_setregs = dummy_proc_setregs;
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ printf("Creating thread %zu\n", i);
+ PTHREAD_REQUIRE
+ (pthread_create(&threads[i], NULL, busyFunction9, NULL));
+ }
+
+ printf("Calling td_open(3)\n");
+ ATF_REQUIRE(td_open(&dummy_callbacks, NULL, &main_ta) == TD_ERR_OK);
+
+ for (i = 0; i < MAX_THREADS; i++) {
+ td_thread_t *td_thread;
+ td_thread_info_t info;
+ ATF_REQUIRE(td_map_pth2thr(main_ta, threads[i], &td_thread)
+ == TD_ERR_OK);
+ ATF_REQUIRE(td_thr_info(td_thread, &info) == TD_ERR_OK);
+ ATF_REQUIRE_EQ(info.thread_state, TD_STATE_RUNNING);
+ }
+
+ ATF_REQUIRE(td_thr_iter(main_ta, iterateThreads9, &count) == TD_ERR_OK);
+
+ exiting9 = 1;
+
+ printf("Calling td_close(3)\n");
+ ATF_REQUIRE(td_close(main_ta) == TD_ERR_OK);
+
+ ATF_REQUIRE_EQ_MSG(count, MAX_THREADS + 1,
+ "counted threads (%d) != expected threads (%zu)",
+ count, MAX_THREADS + 1);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, threads1);
+ ATF_TP_ADD_TC(tp, threads2);
+ ATF_TP_ADD_TC(tp, threads3);
+ ATF_TP_ADD_TC(tp, threads4);
+ ATF_TP_ADD_TC(tp, threads5);
+ ATF_TP_ADD_TC(tp, threads6);
+ ATF_TP_ADD_TC(tp, threads7);
+ ATF_TP_ADD_TC(tp, threads8);
+ ATF_TP_ADD_TC(tp, threads9);
+
+ return atf_no_error();
+}
diff --git a/lib/librefuse/t_refuse_opt.c b/lib/librefuse/t_refuse_opt.c
new file mode 100644
index 000000000000..23c2803f8552
--- /dev/null
+++ b/lib/librefuse/t_refuse_opt.c
@@ -0,0 +1,418 @@
+/* $NetBSD: t_refuse_opt.c,v 1.8 2017/01/13 21:30:41 christos Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_refuse_opt.c,v 1.8 2017/01/13 21:30:41 christos Exp $");
+
+#define _KERNTYPES
+#include <sys/types.h>
+
+#include <atf-c.h>
+
+#include <fuse.h>
+
+#include "h_macros.h"
+
+ATF_TC(t_fuse_opt_add_arg);
+ATF_TC_HEAD(t_fuse_opt_add_arg, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_add_arg(3) works");
+}
+
+ATF_TC_BODY(t_fuse_opt_add_arg, tc)
+{
+ struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
+
+ RZ(fuse_opt_add_arg(&args, "foo"));
+ RZ(fuse_opt_add_arg(&args, "bar"));
+
+ ATF_REQUIRE_EQ(args.argc, 2);
+ ATF_CHECK_STREQ(args.argv[0], "foo");
+ ATF_CHECK_STREQ(args.argv[1], "bar");
+ ATF_CHECK(args.allocated != 0);
+}
+
+ATF_TC(t_fuse_opt_insert_arg);
+ATF_TC_HEAD(t_fuse_opt_insert_arg, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_insert_arg(3) works");
+}
+
+ATF_TC_BODY(t_fuse_opt_insert_arg, tc)
+{
+ struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
+
+ RZ(fuse_opt_insert_arg(&args, 0, "foo"));
+ RZ(fuse_opt_insert_arg(&args, 0, "bar"));
+
+ ATF_REQUIRE_EQ(args.argc, 2);
+ ATF_CHECK_STREQ(args.argv[0], "bar");
+ ATF_CHECK_STREQ(args.argv[1], "foo");
+ ATF_CHECK(args.allocated != 0);
+}
+
+ATF_TC(t_fuse_opt_add_opt);
+ATF_TC_HEAD(t_fuse_opt_add_opt, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_add_opt(3) works");
+}
+
+ATF_TC_BODY(t_fuse_opt_add_opt, tc)
+{
+ char* opt = NULL;
+
+ RZ(fuse_opt_add_opt(&opt, "fo\\o"));
+ ATF_CHECK_STREQ(opt, "fo\\o");
+
+ RZ(fuse_opt_add_opt(&opt, "ba,r"));
+ ATF_CHECK_STREQ(opt, "fo\\o,ba,r");
+}
+
+ATF_TC(t_fuse_opt_add_opt_escaped);
+ATF_TC_HEAD(t_fuse_opt_add_opt_escaped, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_add_opt_escaped(3) works");
+}
+
+ATF_TC_BODY(t_fuse_opt_add_opt_escaped, tc)
+{
+ char* opt = NULL;
+
+ RZ(fuse_opt_add_opt_escaped(&opt, "fo\\o"));
+ ATF_CHECK_STREQ(opt, "fo\\\\o");
+
+ RZ(fuse_opt_add_opt_escaped(&opt, "ba,r"));
+ ATF_CHECK_STREQ(opt, "fo\\\\o,ba\\,r");
+}
+
+ATF_TC(t_fuse_opt_match);
+ATF_TC_HEAD(t_fuse_opt_match, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_match(3) works"
+ " for every form of templates");
+}
+
+ATF_TC_BODY(t_fuse_opt_match, tc)
+{
+ struct fuse_opt o1[] = { FUSE_OPT_KEY("-x" , 0), FUSE_OPT_END };
+ struct fuse_opt o2[] = { FUSE_OPT_KEY("foo" , 0), FUSE_OPT_END };
+ struct fuse_opt o3[] = { FUSE_OPT_KEY("foo=" , 0), FUSE_OPT_END };
+ struct fuse_opt o4[] = { FUSE_OPT_KEY("foo=%s", 0), FUSE_OPT_END };
+ struct fuse_opt o5[] = { FUSE_OPT_KEY("-x " , 0), FUSE_OPT_END };
+ struct fuse_opt o6[] = { FUSE_OPT_KEY("-x %s" , 0), FUSE_OPT_END };
+
+ ATF_CHECK(fuse_opt_match(o1, "-x") == 1);
+ ATF_CHECK(fuse_opt_match(o1, "x") == 0);
+
+ ATF_CHECK(fuse_opt_match(o2, "foo") == 1);
+ ATF_CHECK(fuse_opt_match(o2, "-foo") == 0);
+
+ ATF_CHECK(fuse_opt_match(o3, "foo=bar") == 1);
+ ATF_CHECK(fuse_opt_match(o3, "foo" ) == 0);
+
+ ATF_CHECK(fuse_opt_match(o4, "foo=bar") == 1);
+ ATF_CHECK(fuse_opt_match(o4, "foo" ) == 0);
+
+ ATF_CHECK(fuse_opt_match(o5, "-xbar" ) == 1);
+ ATF_CHECK(fuse_opt_match(o5, "-x" ) == 1);
+ ATF_CHECK(fuse_opt_match(o5, "-x=bar") == 1);
+ ATF_CHECK(fuse_opt_match(o5, "bar" ) == 0);
+
+ ATF_CHECK(fuse_opt_match(o6, "-xbar" ) == 1);
+ ATF_CHECK(fuse_opt_match(o6, "-x" ) == 1);
+ ATF_CHECK(fuse_opt_match(o6, "-x=bar") == 1);
+ ATF_CHECK(fuse_opt_match(o6, "bar" ) == 0);
+}
+
+struct foofs_config {
+ int number;
+ char *string;
+ char* nonopt;
+};
+
+#define FOOFS_OPT(t, p, v) { t, offsetof(struct foofs_config, p), v }
+
+static struct fuse_opt foofs_opts[] = {
+ FOOFS_OPT("number=%i" , number, 0),
+ FOOFS_OPT("-n %i" , number, 0),
+ FOOFS_OPT("string=%s" , string, 0),
+ FOOFS_OPT("number1" , number, 1),
+ FOOFS_OPT("number2" , number, 2),
+ FOOFS_OPT("--number=three", number, 3),
+ FOOFS_OPT("--number=four" , number, 4),
+ FUSE_OPT_END
+};
+
+static int foo_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) {
+ struct foofs_config *config = data;
+
+ if (key == FUSE_OPT_KEY_NONOPT && config->nonopt == NULL) {
+ config->nonopt = strdup(arg);
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
+
+ATF_TC(t_fuse_opt_parse_null_args);
+ATF_TC_HEAD(t_fuse_opt_parse_null_args, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "NULL args means an empty arguments vector");
+}
+
+ATF_TC_BODY(t_fuse_opt_parse_null_args, tc)
+{
+ struct foofs_config config;
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(NULL, &config, NULL, NULL) == 0);
+ ATF_CHECK_EQ(config.number, 0);
+ ATF_CHECK_EQ(config.string, NULL);
+ ATF_CHECK_EQ(config.nonopt, NULL);
+}
+
+ATF_TC(t_fuse_opt_parse_null_opts);
+ATF_TC_HEAD(t_fuse_opt_parse_null_opts, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "NULL opts means an opts array which only has FUSE_OPT_END");
+}
+
+ATF_TC_BODY(t_fuse_opt_parse_null_opts, tc)
+{
+ struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
+ struct foofs_config config;
+
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "-o"));
+ RZ(fuse_opt_add_arg(&args, "number=1,string=foo"));
+ RZ(fuse_opt_add_arg(&args, "bar"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, NULL, NULL) == 0);
+ ATF_CHECK_EQ(config.number, 0);
+ ATF_CHECK_EQ(config.string, NULL);
+ ATF_CHECK_EQ(config.nonopt, NULL);
+ ATF_CHECK_EQ(args.argc, 4);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+ ATF_CHECK_STREQ(args.argv[1], "-o");
+ ATF_CHECK_STREQ(args.argv[2], "number=1,string=foo");
+ ATF_CHECK_STREQ(args.argv[3], "bar");
+}
+
+ATF_TC(t_fuse_opt_parse_null_proc);
+ATF_TC_HEAD(t_fuse_opt_parse_null_proc, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "NULL proc means a processor function always returning 1,"
+ " i.e. keep the argument");
+}
+
+ATF_TC_BODY(t_fuse_opt_parse_null_proc, tc)
+{
+ struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
+ struct foofs_config config;
+
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "-o"));
+ RZ(fuse_opt_add_arg(&args, "number=1,string=foo"));
+ RZ(fuse_opt_add_arg(&args, "bar"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, NULL) == 0);
+ ATF_CHECK_EQ(config.number, 1);
+ ATF_CHECK_STREQ(config.string, "foo");
+ ATF_CHECK_EQ(config.nonopt, NULL);
+ ATF_CHECK_EQ(args.argc, 2);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+ ATF_CHECK_STREQ(args.argv[1], "bar");
+}
+
+ATF_TC(t_fuse_opt_parse);
+ATF_TC_HEAD(t_fuse_opt_parse, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_parse(3) fully works");
+}
+
+ATF_TC_BODY(t_fuse_opt_parse, tc)
+{
+ struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
+ struct foofs_config config;
+
+ /* Standard form */
+ fuse_opt_free_args(&args);
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "-o"));
+ RZ(fuse_opt_add_arg(&args, "number=1,string=foo"));
+ RZ(fuse_opt_add_arg(&args, "bar"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
+ ATF_CHECK_EQ(config.number, 1);
+ ATF_CHECK_STREQ(config.string, "foo");
+ ATF_CHECK_STREQ(config.nonopt, "bar");
+ ATF_CHECK_EQ(args.argc, 1);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+
+ /* Concatenated -o */
+ fuse_opt_free_args(&args);
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "-onumber=1,unknown,string=foo"));
+ RZ(fuse_opt_add_arg(&args, "bar"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
+ ATF_CHECK_EQ(config.number, 1);
+ ATF_CHECK_STREQ(config.string, "foo");
+ ATF_CHECK_STREQ(config.nonopt, "bar");
+ ATF_CHECK_EQ(args.argc, 3);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+ ATF_CHECK_STREQ(args.argv[1], "-o");
+ ATF_CHECK_STREQ(args.argv[2], "unknown");
+
+ /* Sparse -o */
+ fuse_opt_free_args(&args);
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "bar"));
+ RZ(fuse_opt_add_arg(&args, "baz"));
+ RZ(fuse_opt_add_arg(&args, "-o"));
+ RZ(fuse_opt_add_arg(&args, "number=1"));
+ RZ(fuse_opt_add_arg(&args, "-o"));
+ RZ(fuse_opt_add_arg(&args, "unknown"));
+ RZ(fuse_opt_add_arg(&args, "-o"));
+ RZ(fuse_opt_add_arg(&args, "string=foo"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
+ ATF_CHECK_EQ(config.number, 1);
+ ATF_CHECK_STREQ(config.string, "foo");
+ ATF_CHECK_STREQ(config.nonopt, "bar");
+ ATF_CHECK_EQ(args.argc, 4);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+ ATF_CHECK_STREQ(args.argv[1], "-o");
+ ATF_CHECK_STREQ(args.argv[2], "unknown");
+ ATF_CHECK_STREQ(args.argv[3], "baz");
+
+ /* Separate -n %i */
+ fuse_opt_free_args(&args);
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "-n"));
+ RZ(fuse_opt_add_arg(&args, "3"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
+ ATF_CHECK_EQ(config.number, 3);
+ ATF_CHECK_EQ(config.string, NULL);
+ ATF_CHECK_EQ(config.nonopt, NULL);
+ ATF_CHECK_EQ(args.argc, 1);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+
+ /* Concatenated -n %i */
+ fuse_opt_free_args(&args);
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "-n3"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
+ ATF_CHECK_EQ(config.number, 3);
+ ATF_CHECK_EQ(config.string, NULL);
+ ATF_CHECK_EQ(config.nonopt, NULL);
+ ATF_CHECK_EQ(args.argc, 1);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+
+ /* -o constant */
+ fuse_opt_free_args(&args);
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "-o"));
+ RZ(fuse_opt_add_arg(&args, "number2"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
+ ATF_CHECK_EQ(config.number, 2);
+ ATF_CHECK_EQ(config.string, NULL);
+ ATF_CHECK_EQ(config.nonopt, NULL);
+ ATF_CHECK_EQ(args.argc, 1);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+
+ /* -x constant */
+ fuse_opt_free_args(&args);
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "--number=four"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
+ ATF_CHECK_EQ(config.number, 4);
+ ATF_CHECK_EQ(config.string, NULL);
+ ATF_CHECK_EQ(config.nonopt, NULL);
+ ATF_CHECK_EQ(args.argc, 1);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+
+ /* end-of-options "--" marker */
+ fuse_opt_free_args(&args);
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "--"));
+ RZ(fuse_opt_add_arg(&args, "-onumber=1"));
+ RZ(fuse_opt_add_arg(&args, "-ostring=foo"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
+ ATF_CHECK_EQ(config.number, 0);
+ ATF_CHECK_EQ(config.string, NULL);
+ ATF_CHECK_STREQ(config.nonopt, "-onumber=1");
+ ATF_CHECK_EQ(args.argc, 3);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+ ATF_CHECK_STREQ(args.argv[1], "--");
+ ATF_CHECK_STREQ(args.argv[2], "-ostring=foo");
+
+ /* The "--" marker at the last of outargs should be removed */
+ fuse_opt_free_args(&args);
+ RZ(fuse_opt_add_arg(&args, "foofs"));
+ RZ(fuse_opt_add_arg(&args, "--"));
+ RZ(fuse_opt_add_arg(&args, "-onumber=1"));
+
+ memset(&config, 0, sizeof(config));
+ ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
+ ATF_CHECK_EQ(config.number, 0);
+ ATF_CHECK_EQ(config.string, NULL);
+ ATF_CHECK_STREQ(config.nonopt, "-onumber=1");
+ ATF_CHECK_EQ(args.argc, 1);
+ ATF_CHECK_STREQ(args.argv[0], "foofs");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, t_fuse_opt_add_arg);
+ ATF_TP_ADD_TC(tp, t_fuse_opt_insert_arg);
+ ATF_TP_ADD_TC(tp, t_fuse_opt_add_opt);
+ ATF_TP_ADD_TC(tp, t_fuse_opt_add_opt_escaped);
+ ATF_TP_ADD_TC(tp, t_fuse_opt_match);
+ ATF_TP_ADD_TC(tp, t_fuse_opt_parse_null_args);
+ ATF_TP_ADD_TC(tp, t_fuse_opt_parse_null_opts);
+ ATF_TP_ADD_TC(tp, t_fuse_opt_parse_null_proc);
+ ATF_TP_ADD_TC(tp, t_fuse_opt_parse);
+
+ return atf_no_error();
+}
diff --git a/net/if_tun/t_tun.sh b/net/if_tun/t_tun.sh
new file mode 100755
index 000000000000..87df39ab5886
--- /dev/null
+++ b/net/if_tun/t_tun.sh
@@ -0,0 +1,138 @@
+# $NetBSD: t_tun.sh,v 1.4 2016/11/07 05:25:37 ozaki-r Exp $
+#
+# Copyright (c) 2016 Internet Initiative Japan Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+RUMP_FLAGS="-lrumpnet -lrumpnet_net -lrumpnet_netinet -lrumpnet_netinet6"
+RUMP_FLAGS="$RUMP_FLAGS -lrumpnet_shmif -lrumpnet_tun -lrumpdev"
+
+BUS=bus
+SOCK_LOCAL=unix://commsock1
+SOCK_REMOTE=unix://commsock2
+IP_LOCAL=10.0.0.1
+IP_REMOTE=10.0.0.2
+
+DEBUG=${DEBUG:-true}
+
+atf_test_case tun_create_destroy cleanup
+tun_create_destroy_head()
+{
+
+ atf_set "descr" "tests of creation and deletion of tun interface"
+ atf_set "require.progs" "rump_server"
+}
+
+tun_create_destroy_body()
+{
+
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${SOCK_LOCAL}
+
+ export RUMP_SERVER=${SOCK_LOCAL}
+
+ atf_check -s exit:0 rump.ifconfig tun0 create
+ atf_check -s exit:0 rump.ifconfig tun0 up
+ atf_check -s exit:0 rump.ifconfig tun0 down
+ atf_check -s exit:0 rump.ifconfig tun0 destroy
+}
+
+tun_create_destroy_cleanup()
+{
+
+ RUMP_SERVER=${SOCK_LOCAL} rump.halt
+}
+
+atf_test_case tun_setup cleanup
+tun_setup_head()
+{
+
+ atf_set "descr" "tests of setting up a tunnel"
+ atf_set "require.progs" "rump_server"
+}
+
+check_route_entry()
+{
+ local ip=$(echo $1 |sed 's/\./\\./g')
+ local gw=$2
+ local flags=$3
+ local iface=$4
+
+ atf_check -s exit:0 -o match:" $flags " -e ignore -x \
+ "rump.netstat -rn -f inet | grep ^'$ip'"
+ atf_check -s exit:0 -o match:" $gw " -e ignore -x \
+ "rump.netstat -rn -f inet | grep ^'$ip'"
+ atf_check -s exit:0 -o match:" $iface" -e ignore -x \
+ "rump.netstat -rn -f inet | grep ^'$ip'"
+}
+
+tun_setup_body()
+{
+
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${SOCK_LOCAL}
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${SOCK_REMOTE}
+
+ export RUMP_SERVER=${SOCK_LOCAL}
+
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr $BUS
+ atf_check -s exit:0 rump.ifconfig shmif0 ${IP_LOCAL}/24 up
+ atf_check -s exit:0 rump.ifconfig -w 10
+
+ export RUMP_SERVER=${SOCK_REMOTE}
+
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr $BUS
+ atf_check -s exit:0 rump.ifconfig shmif0 ${IP_REMOTE}/24 up
+ atf_check -s exit:0 rump.ifconfig -w 10
+
+ export RUMP_SERVER=${SOCK_LOCAL}
+ atf_check -s exit:0 rump.ifconfig tun0 create
+ atf_check -s exit:0 rump.ifconfig tun0 ${IP_LOCAL} ${IP_REMOTE} up
+ atf_check -s exit:0 \
+ -o match:"inet ${IP_LOCAL}/32 -> ${IP_REMOTE}" rump.ifconfig tun0
+ $DEBUG && rump.netstat -nr -f inet
+ check_route_entry ${IP_REMOTE} ${IP_LOCAL} UH tun0
+
+ export RUMP_SERVER=${SOCK_REMOTE}
+ atf_check -s exit:0 rump.ifconfig tun0 create
+ atf_check -s exit:0 rump.ifconfig tun0 ${IP_REMOTE} ${IP_LOCAL} up
+ atf_check -s exit:0 \
+ -o match:"inet ${IP_REMOTE}/32 -> ${IP_LOCAL}" rump.ifconfig tun0
+ $DEBUG && rump.netstat -nr -f inet
+ check_route_entry ${IP_LOCAL} ${IP_REMOTE} UH tun0
+}
+
+tun_setup_cleanup()
+{
+
+ RUMP_SERVER=${SOCK_LOCAL} rump.halt
+ RUMP_SERVER=${SOCK_REMOTE} rump.halt
+}
+
+atf_init_test_cases()
+{
+
+ atf_add_test_case tun_create_destroy
+ atf_add_test_case tun_setup
+}
diff --git a/net/if_vlan/t_vlan.sh b/net/if_vlan/t_vlan.sh
new file mode 100755
index 000000000000..a6902fb1e247
--- /dev/null
+++ b/net/if_vlan/t_vlan.sh
@@ -0,0 +1,115 @@
+# $NetBSD: t_vlan.sh,v 1.1 2016/11/26 03:19:49 ozaki-r Exp $
+#
+# Copyright (c) 2016 Internet Initiative Japan Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+BUS=bus
+SOCK_LOCAL=unix://commsock1
+SOCK_REMOTE=unix://commsock2
+IP_LOCAL=10.0.0.1
+IP_REMOTE=10.0.0.2
+
+DEBUG=${DEBUG:-false}
+
+atf_test_case vlan_create_destroy cleanup
+vlan_create_destroy_head()
+{
+
+ atf_set "descr" "tests of creation and deletion of vlan interface"
+ atf_set "require.progs" "rump_server"
+}
+
+vlan_create_destroy_body()
+{
+
+ rump_server_start $SOCK_LOCAL vlan
+
+ export RUMP_SERVER=${SOCK_LOCAL}
+
+ atf_check -s exit:0 rump.ifconfig vlan0 create
+ atf_check -s exit:0 rump.ifconfig vlan0 up
+ atf_check -s exit:0 rump.ifconfig vlan0 down
+ atf_check -s exit:0 rump.ifconfig vlan0 destroy
+}
+
+vlan_create_destroy_cleanup()
+{
+
+ $DEBUG && dump
+ cleanup
+}
+
+atf_test_case vlan_basic cleanup
+vlan_basic_head()
+{
+
+ atf_set "descr" "tests of communications over vlan interfaces"
+ atf_set "require.progs" "rump_server"
+}
+
+vlan_basic_body()
+{
+
+ rump_server_start $SOCK_LOCAL vlan
+ rump_server_add_iface $SOCK_LOCAL shmif0 $BUS
+ rump_server_start $SOCK_REMOTE vlan
+ rump_server_add_iface $SOCK_REMOTE shmif0 $BUS
+
+ export RUMP_SERVER=$SOCK_LOCAL
+ atf_check -s exit:0 rump.ifconfig shmif0 up
+ export RUMP_SERVER=$SOCK_REMOTE
+ atf_check -s exit:0 rump.ifconfig shmif0 up
+
+ export RUMP_SERVER=$SOCK_LOCAL
+ atf_check -s exit:0 rump.ifconfig vlan0 create
+ atf_check -s exit:0 rump.ifconfig vlan0 vlan 10 vlanif shmif0
+ atf_check -s exit:0 rump.ifconfig vlan0 $IP_LOCAL/24
+ atf_check -s exit:0 rump.ifconfig vlan0 up
+ atf_check -s exit:0 rump.ifconfig -w 10
+
+ export RUMP_SERVER=$SOCK_REMOTE
+ atf_check -s exit:0 rump.ifconfig vlan0 create
+ atf_check -s exit:0 rump.ifconfig vlan0 vlan 10 vlanif shmif0
+ atf_check -s exit:0 rump.ifconfig vlan0 $IP_REMOTE/24
+ atf_check -s exit:0 rump.ifconfig vlan0 up
+ atf_check -s exit:0 rump.ifconfig -w 10
+
+ export RUMP_SERVER=$SOCK_LOCAL
+ atf_check -s exit:0 -o ignore rump.ping -n -w 1 -c 1 $IP_REMOTE
+}
+
+vlan_basic_cleanup()
+{
+
+ $DEBUG && dump
+ cleanup
+}
+
+atf_init_test_cases()
+{
+
+ atf_add_test_case vlan_create_destroy
+ atf_add_test_case vlan_basic
+}
diff --git a/sys/uvm/t_uvm_physseg.c b/sys/uvm/t_uvm_physseg.c
new file mode 100644
index 000000000000..a5f2fa9e9067
--- /dev/null
+++ b/sys/uvm/t_uvm_physseg.c
@@ -0,0 +1,2377 @@
+/* $NetBSD: t_uvm_physseg.c,v 1.2 2016/12/22 08:15:20 cherry Exp $ */
+
+/*-
+ * Copyright (c) 2015, 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Santhosh N. Raju <santhosh.raju@gmail.com> and
+ * by Cherry G. Mathew
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_uvm_physseg.c,v 1.2 2016/12/22 08:15:20 cherry Exp $");
+
+/*
+ * If this line is commented out tests related to uvm_physseg_get_pmseg()
+ * wont run.
+ *
+ * Have a look at machine/uvm_physseg.h for more details.
+ */
+#define __HAVE_PMAP_PHYSSEG
+
+/*
+ * This is a dummy struct used for testing purposes
+ *
+ * In reality this struct would exist in the MD part of the code residing in
+ * machines/vmparam.h
+ */
+
+#ifdef __HAVE_PMAP_PHYSSEG
+struct pmap_physseg {
+ int dummy_variable; /* Dummy variable use for testing */
+};
+#endif
+
+/* Testing API - assumes userland */
+/* Provide Kernel API equivalents */
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h> /* memset(3) et. al */
+#include <stdio.h> /* printf(3) */
+#include <stdlib.h> /* malloc(3) */
+#include <stdarg.h>
+#include <stddef.h>
+
+#define PRIxPADDR "lx"
+#define PRIxPSIZE "lx"
+#define PRIuPSIZE "lu"
+#define PRIxVADDR "lx"
+#define PRIxVSIZE "lx"
+#define PRIuVSIZE "lu"
+
+#define UVM_HOTPLUG /* Enable hotplug with rbtree. */
+#define PMAP_STEAL_MEMORY
+#define DEBUG /* Enable debug functionality. */
+
+typedef unsigned long vaddr_t;
+typedef unsigned long paddr_t;
+typedef unsigned long psize_t;
+typedef unsigned long vsize_t;
+
+#include <uvm/uvm_physseg.h>
+#include <uvm/uvm_page.h>
+
+#ifndef DIAGNOSTIC
+#define KASSERTMSG(e, msg, ...) /* NOTHING */
+#define KASSERT(e) /* NOTHING */
+#else
+#define KASSERT(a) assert(a)
+#define KASSERTMSG(exp, ...) printf(__VA_ARGS__); assert((exp))
+#endif
+
+#define VM_PHYSSEG_STRAT VM_PSTRAT_BSEARCH
+
+#define VM_NFREELIST 4
+#define VM_FREELIST_DEFAULT 0
+#define VM_FREELIST_FIRST16 3
+#define VM_FREELIST_FIRST1G 2
+#define VM_FREELIST_FIRST4G 1
+
+/*
+ * Used in tests when Array implementation is tested
+ */
+#if !defined(VM_PHYSSEG_MAX)
+#define VM_PHYSSEG_MAX 1
+#endif
+
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define PAGE_MASK (PAGE_SIZE - 1)
+#define atop(x) (((paddr_t)(x)) >> PAGE_SHIFT)
+#define ptoa(x) (((paddr_t)(x)) << PAGE_SHIFT)
+
+#define mutex_enter(l)
+#define mutex_exit(l)
+
+psize_t physmem;
+
+struct uvmexp uvmexp; /* decl */
+
+/*
+ * uvm structure borrowed from uvm.h
+ *
+ * Remember this is a dummy structure used within the ATF Tests and
+ * uses only necessary fields from the original uvm struct.
+ * See uvm/uvm.h for the full struct.
+ */
+
+struct uvm {
+ /* vm_page related parameters */
+
+ bool page_init_done; /* TRUE if uvm_page_init() finished */
+} uvm;
+
+#include <sys/kmem.h>
+
+void *
+kmem_alloc(size_t size, km_flag_t flags)
+{
+ return malloc(size);
+}
+
+void *
+kmem_zalloc(size_t size, km_flag_t flags)
+{
+ void *ptr;
+ ptr = malloc(size);
+
+ memset(ptr, 0, size);
+
+ return ptr;
+}
+
+void
+kmem_free(void *mem, size_t size)
+{
+ free(mem);
+}
+
+static void
+panic(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ printf("\n");
+ va_end(ap);
+ KASSERT(false);
+
+ /*NOTREACHED*/
+}
+
+static void
+uvm_pagefree(struct vm_page *pg)
+{
+ return;
+}
+
+#if defined(UVM_HOTPLUG)
+static void
+uvmpdpol_reinit(void)
+{
+ return;
+}
+#endif /* UVM_HOTPLUG */
+
+/* end - Provide Kernel API equivalents */
+
+
+#include "uvm/uvm_physseg.c"
+
+#include <atf-c.h>
+
+#define SIXTYFOUR_KILO (64 * 1024)
+#define ONETWENTYEIGHT_KILO (128 * 1024)
+#define TWOFIFTYSIX_KILO (256 * 1024)
+#define FIVEONETWO_KILO (512 * 1024)
+#define ONE_MEGABYTE (1024 * 1024)
+#define TWO_MEGABYTE (2 * 1024 * 1024)
+
+/* Sample Page Frame Numbers */
+#define VALID_START_PFN_1 atop(0)
+#define VALID_END_PFN_1 atop(ONE_MEGABYTE)
+#define VALID_AVAIL_START_PFN_1 atop(0)
+#define VALID_AVAIL_END_PFN_1 atop(ONE_MEGABYTE)
+
+#define VALID_START_PFN_2 atop(ONE_MEGABYTE + 1)
+#define VALID_END_PFN_2 atop(ONE_MEGABYTE * 2)
+#define VALID_AVAIL_START_PFN_2 atop(ONE_MEGABYTE + 1)
+#define VALID_AVAIL_END_PFN_2 atop(ONE_MEGABYTE * 2)
+
+#define VALID_START_PFN_3 atop((ONE_MEGABYTE * 2) + 1)
+#define VALID_END_PFN_3 atop(ONE_MEGABYTE * 3)
+#define VALID_AVAIL_START_PFN_3 atop((ONE_MEGABYTE * 2) + 1)
+#define VALID_AVAIL_END_PFN_3 atop(ONE_MEGABYTE * 3)
+
+#define VALID_START_PFN_4 atop((ONE_MEGABYTE * 3) + 1)
+#define VALID_END_PFN_4 atop(ONE_MEGABYTE * 4)
+#define VALID_AVAIL_START_PFN_4 atop((ONE_MEGABYTE * 3) + 1)
+#define VALID_AVAIL_END_PFN_4 atop(ONE_MEGABYTE * 4)
+
+/*
+ * Total number of pages (of 4K size each) should be 256 for 1MB of memory.
+ */
+#define PAGE_COUNT_1M 256
+
+/*
+ * A debug fucntion to print the content of upm.
+ */
+ static inline void
+ uvm_physseg_dump_seg(uvm_physseg_t upm)
+ {
+#if defined(DEBUG)
+ printf("%s: seg->start == %ld\n", __func__,
+ uvm_physseg_get_start(upm));
+ printf("%s: seg->end == %ld\n", __func__,
+ uvm_physseg_get_end(upm));
+ printf("%s: seg->avail_start == %ld\n", __func__,
+ uvm_physseg_get_avail_start(upm));
+ printf("%s: seg->avail_end == %ld\n", __func__,
+ uvm_physseg_get_avail_end(upm));
+
+ printf("====\n\n");
+#else
+ return;
+#endif /* DEBUG */
+ }
+
+/*
+ * Private accessor that gets the value of uvm_physseg_graph.nentries
+ */
+static int
+uvm_physseg_get_entries(void)
+{
+#if defined(UVM_HOTPLUG)
+ return uvm_physseg_graph.nentries;
+#else
+ return vm_nphysmem;
+#endif /* UVM_HOTPLUG */
+}
+
+#if !defined(UVM_HOTPLUG)
+static void *
+uvm_physseg_alloc(size_t sz)
+{
+ return &vm_physmem[vm_nphysseg++];
+}
+#endif
+
+/*
+ * Test Fixture SetUp().
+ */
+static void
+setup(void)
+{
+ /* Prerequisites for running certain calls in uvm_physseg */
+ uvmexp.pagesize = PAGE_SIZE;
+ uvmexp.npages = 0;
+ uvm.page_init_done = false;
+ uvm_physseg_init();
+}
+
+
+/* <---- Tests for Internal functions ----> */
+#if defined(UVM_HOTPLUG)
+ATF_TC(uvm_physseg_alloc_atboot_mismatch);
+ATF_TC_HEAD(uvm_physseg_alloc_atboot_mismatch, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "boot time uvm_physseg_alloc() sanity"
+ "size mismatch alloc() test.");
+}
+
+ATF_TC_BODY(uvm_physseg_alloc_atboot_mismatch, tc)
+{
+ uvm.page_init_done = false;
+
+ atf_tc_expect_signal(SIGABRT, "size mismatch alloc()");
+
+ uvm_physseg_alloc(sizeof(struct uvm_physseg) - 1);
+}
+
+ATF_TC(uvm_physseg_alloc_atboot_overrun);
+ATF_TC_HEAD(uvm_physseg_alloc_atboot_overrun, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "boot time uvm_physseg_alloc() sanity"
+ "array overrun alloc() test.");
+}
+
+ATF_TC_BODY(uvm_physseg_alloc_atboot_overrun, tc)
+{
+ uvm.page_init_done = false;
+
+ atf_tc_expect_signal(SIGABRT, "array overrun alloc()");
+
+ uvm_physseg_alloc((VM_PHYSSEG_MAX + 1) * sizeof(struct uvm_physseg));
+
+}
+
+ATF_TC(uvm_physseg_alloc_sanity);
+ATF_TC_HEAD(uvm_physseg_alloc_sanity, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "further uvm_physseg_alloc() sanity checks");
+}
+
+ATF_TC_BODY(uvm_physseg_alloc_sanity, tc)
+{
+
+ /* At boot time */
+ uvm.page_init_done = false;
+
+ /* Correct alloc */
+ ATF_REQUIRE(uvm_physseg_alloc(VM_PHYSSEG_MAX * sizeof(struct uvm_physseg)));
+
+ /* Retry static alloc()s as dynamic - we expect them to pass */
+ uvm.page_init_done = true;
+ ATF_REQUIRE(uvm_physseg_alloc(sizeof(struct uvm_physseg) - 1));
+ ATF_REQUIRE(uvm_physseg_alloc(2 * VM_PHYSSEG_MAX * sizeof(struct uvm_physseg)));
+}
+
+ATF_TC(uvm_physseg_free_atboot_mismatch);
+ATF_TC_HEAD(uvm_physseg_free_atboot_mismatch, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "boot time uvm_physseg_free() sanity"
+ "size mismatch free() test.");
+}
+
+ATF_TC_BODY(uvm_physseg_free_atboot_mismatch, tc)
+{
+ uvm.page_init_done = false;
+
+ atf_tc_expect_signal(SIGABRT, "size mismatch free()");
+
+ uvm_physseg_free(&uvm_physseg[0], sizeof(struct uvm_physseg) - 1);
+}
+
+ATF_TC(uvm_physseg_free_sanity);
+ATF_TC_HEAD(uvm_physseg_free_sanity, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "further uvm_physseg_free() sanity checks");
+}
+
+ATF_TC_BODY(uvm_physseg_free_sanity, tc)
+{
+
+ /* At boot time */
+ uvm.page_init_done = false;
+
+ struct uvm_physseg *seg;
+
+#if VM_PHYSSEG_MAX > 1
+ /*
+ * Note: free()ing the entire array is considered to be an
+ * error. Thus VM_PHYSSEG_MAX - 1.
+ */
+
+ seg = uvm_physseg_alloc((VM_PHYSSEG_MAX - 1) * sizeof(*seg));
+ uvm_physseg_free(seg, (VM_PHYSSEG_MAX - 1) * sizeof(struct uvm_physseg));
+#endif
+
+ /* Retry static alloc()s as dynamic - we expect them to pass */
+ uvm.page_init_done = true;
+
+ seg = uvm_physseg_alloc(sizeof(struct uvm_physseg) - 1);
+ uvm_physseg_free(seg, sizeof(struct uvm_physseg) - 1);
+
+ seg = uvm_physseg_alloc(2 * VM_PHYSSEG_MAX * sizeof(struct uvm_physseg));
+
+ uvm_physseg_free(seg, 2 * VM_PHYSSEG_MAX * sizeof(struct uvm_physseg));
+}
+
+#if VM_PHYSSEG_MAX > 1
+ATF_TC(uvm_physseg_atboot_free_leak);
+ATF_TC_HEAD(uvm_physseg_atboot_free_leak, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "does free() leak at boot ?\n"
+ "This test needs VM_PHYSSEG_MAX > 1)");
+}
+
+ATF_TC_BODY(uvm_physseg_atboot_free_leak, tc)
+{
+
+ /* At boot time */
+ uvm.page_init_done = false;
+
+ /* alloc to array size */
+ struct uvm_physseg *seg;
+ seg = uvm_physseg_alloc(VM_PHYSSEG_MAX * sizeof(*seg));
+
+ uvm_physseg_free(seg, sizeof(*seg));
+
+ atf_tc_expect_signal(SIGABRT, "array overrun on alloc() after leak");
+
+ ATF_REQUIRE(uvm_physseg_alloc(sizeof(struct uvm_physseg)));
+}
+#endif /* VM_PHYSSEG_MAX */
+#endif /* UVM_HOTPLUG */
+
+/*
+ * Note: This function replicates verbatim what happens in
+ * uvm_page.c:uvm_page_init().
+ *
+ * Please track any changes that happen there.
+ */
+static void
+uvm_page_init_fake(struct vm_page *pagearray, psize_t pagecount)
+{
+ uvm_physseg_t bank;
+ size_t n;
+
+ for (bank = uvm_physseg_get_first(),
+ uvm_physseg_seg_chomp_slab(bank, pagearray, pagecount);
+ uvm_physseg_valid_p(bank);
+ bank = uvm_physseg_get_next(bank)) {
+
+ n = uvm_physseg_get_end(bank) - uvm_physseg_get_start(bank);
+ uvm_physseg_seg_alloc_from_slab(bank, n);
+ uvm_physseg_init_seg(bank, pagearray);
+
+ /* set up page array pointers */
+ pagearray += n;
+ pagecount -= n;
+ }
+
+ uvm.page_init_done = true;
+}
+
+ATF_TC(uvm_physseg_plug);
+ATF_TC_HEAD(uvm_physseg_plug, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test plug functionality.");
+}
+/* Note: We only do the second boot time plug if VM_PHYSSEG_MAX > 1 */
+ATF_TC_BODY(uvm_physseg_plug, tc)
+{
+ int nentries = 0; /* Count of entries via plug done so far */
+ uvm_physseg_t upm1;
+#if VM_PHYSSEG_MAX > 2
+ uvm_physseg_t upm2;
+#endif
+
+#if VM_PHYSSEG_MAX > 1
+ uvm_physseg_t upm3;
+#endif
+ uvm_physseg_t upm4;
+ psize_t npages1 = (VALID_END_PFN_1 - VALID_START_PFN_1);
+ psize_t npages2 = (VALID_END_PFN_2 - VALID_START_PFN_2);
+ psize_t npages3 = (VALID_END_PFN_3 - VALID_START_PFN_3);
+ psize_t npages4 = (VALID_END_PFN_4 - VALID_START_PFN_4);
+ struct vm_page *pgs, *slab = malloc(sizeof(struct vm_page) * (npages1
+#if VM_PHYSSEG_MAX > 2
+ + npages2
+#endif
+ + npages3));
+
+ /* Fake early boot */
+
+ setup();
+
+ /* Vanilla plug x 2 */
+ ATF_REQUIRE_EQ(uvm_physseg_plug(VALID_START_PFN_1, npages1, &upm1), true);
+ ATF_REQUIRE_EQ(++nentries, uvm_physseg_get_entries());
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+#if VM_PHYSSEG_MAX > 2
+ ATF_REQUIRE_EQ(uvm_physseg_plug(VALID_START_PFN_2, npages2, &upm2), true);
+ ATF_REQUIRE_EQ(++nentries, uvm_physseg_get_entries());
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+#endif
+ /* Post boot: Fake all segments and pages accounted for. */
+ uvm_page_init_fake(slab, npages1 + npages2 + npages3);
+
+ ATF_CHECK_EQ(npages1
+#if VM_PHYSSEG_MAX > 2
+ + npages2
+#endif
+ , uvmexp.npages);
+#if VM_PHYSSEG_MAX > 1
+ /* Scavenge plug - goes into the same slab */
+ ATF_REQUIRE_EQ(uvm_physseg_plug(VALID_START_PFN_3, npages3, &upm3), true);
+ ATF_REQUIRE_EQ(++nentries, uvm_physseg_get_entries());
+ ATF_REQUIRE_EQ(npages1
+#if VM_PHYSSEG_MAX > 2
+ + npages2
+#endif
+ + npages3, uvmexp.npages);
+
+ /* Scavenge plug should fit right in the slab */
+ pgs = uvm_physseg_get_pg(upm3, 0);
+ ATF_REQUIRE(pgs > slab && pgs < (slab + npages1 + npages2 + npages3));
+#endif
+ /* Hot plug - goes into a brand new slab */
+ ATF_REQUIRE_EQ(uvm_physseg_plug(VALID_START_PFN_4, npages4, &upm4), true);
+ /* The hot plug slab should have nothing to do with the original slab */
+ pgs = uvm_physseg_get_pg(upm4, 0);
+ ATF_REQUIRE(pgs < slab || pgs > (slab + npages1
+#if VM_PHYSSEG_MAX > 2
+ + npages2
+#endif
+ + npages3));
+
+}
+ATF_TC(uvm_physseg_unplug);
+ATF_TC_HEAD(uvm_physseg_unplug, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test unplug functionality.");
+}
+ATF_TC_BODY(uvm_physseg_unplug, tc)
+{
+ paddr_t pa = 0;
+
+ psize_t npages1 = (VALID_END_PFN_1 - VALID_START_PFN_1);
+ psize_t npages2 = (VALID_END_PFN_2 - VALID_START_PFN_2);
+ psize_t npages3 = (VALID_END_PFN_3 - VALID_START_PFN_3);
+
+ struct vm_page *slab = malloc(sizeof(struct vm_page) * (npages1 + npages2 + npages3));
+
+ uvm_physseg_t upm;
+
+ /* Boot time */
+ setup();
+
+ /* We start with zero segments */
+ ATF_REQUIRE_EQ(true, uvm_physseg_plug(atop(0), atop(ONE_MEGABYTE), NULL));
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+ /* Do we have an arbitrary offset in there ? */
+ uvm_physseg_find(atop(TWOFIFTYSIX_KILO), &pa);
+ ATF_REQUIRE_EQ(pa, atop(TWOFIFTYSIX_KILO));
+ ATF_REQUIRE_EQ(0, uvmexp.npages); /* Boot time sanity */
+
+#if VM_PHYSSEG_MAX == 1
+ /*
+ * This is the curious case at boot time, of having one
+ * extent(9) static entry per segment, which means that a
+ * fragmenting unplug will fail.
+ */
+ atf_tc_expect_signal(SIGABRT, "fragmenting unplug for single segment");
+
+ /*
+ * In order to test the fragmenting cases, please set
+ * VM_PHYSSEG_MAX > 1
+ */
+#endif
+ /* Now let's unplug from the middle */
+ ATF_REQUIRE_EQ(true, uvm_physseg_unplug(atop(TWOFIFTYSIX_KILO), atop(FIVEONETWO_KILO)));
+ /* verify that a gap exists at TWOFIFTYSIX_KILO */
+ pa = 0; /* reset */
+ uvm_physseg_find(atop(TWOFIFTYSIX_KILO), &pa);
+ ATF_REQUIRE_EQ(pa, 0);
+
+ /* Post boot: Fake all segments and pages accounted for. */
+ uvm_page_init_fake(slab, npages1 + npages2 + npages3);
+ /* Account for the unplug */
+ ATF_CHECK_EQ(atop(FIVEONETWO_KILO), uvmexp.npages);
+
+ /* Original entry should fragment into two */
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ upm = uvm_physseg_find(atop(TWOFIFTYSIX_KILO + FIVEONETWO_KILO), NULL);
+
+ ATF_REQUIRE(uvm_physseg_valid_p(upm));
+
+ /* Now unplug the tail fragment - should swallow the complete entry */
+ ATF_REQUIRE_EQ(true, uvm_physseg_unplug(atop(TWOFIFTYSIX_KILO + FIVEONETWO_KILO), atop(TWOFIFTYSIX_KILO)));
+
+ /* The "swallow" above should have invalidated the handle */
+ ATF_REQUIRE_EQ(false, uvm_physseg_valid_p(upm));
+
+ /* Only the first one is left now */
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ /* Unplug from the back */
+ ATF_REQUIRE_EQ(true, uvm_physseg_unplug(atop(ONETWENTYEIGHT_KILO), atop(ONETWENTYEIGHT_KILO)));
+ /* Shouldn't change the number of segments */
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ /* Unplug from the front */
+ ATF_REQUIRE_EQ(true, uvm_physseg_unplug(0, atop(SIXTYFOUR_KILO)));
+ /* Shouldn't change the number of segments */
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ /* Unplugging the final fragment should fail */
+ atf_tc_expect_signal(SIGABRT, "Unplugging the last segment");
+ ATF_REQUIRE_EQ(true, uvm_physseg_unplug(atop(SIXTYFOUR_KILO), atop(SIXTYFOUR_KILO)));
+}
+
+
+/* <---- end Tests for Internal functions ----> */
+
+/* Tests for functions exported via uvm_physseg.h */
+ATF_TC(uvm_physseg_init);
+ATF_TC_HEAD(uvm_physseg_init, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_init() call\
+ initializes the vm_physmem struct which holds the rb_tree.");
+}
+ATF_TC_BODY(uvm_physseg_init, tc)
+{
+ uvm_physseg_init();
+
+ ATF_REQUIRE_EQ(0, uvm_physseg_get_entries());
+}
+
+ATF_TC(uvm_page_physload_preload);
+ATF_TC_HEAD(uvm_page_physload_preload, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physload() \
+ call works without a panic() in a preload scenario.");
+}
+ATF_TC_BODY(uvm_page_physload_preload, tc)
+{
+ uvm_physseg_t upm;
+
+ setup();
+
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ /* Should return a valid handle */
+ ATF_REQUIRE(uvm_physseg_valid_p(upm));
+
+ /* No pages should be allocated yet */
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ /* After the first call one segment should exist */
+ ATF_CHECK_EQ(1, uvm_physseg_get_entries());
+
+ /* Insert more than one segment iff VM_PHYSSEG_MAX > 1 */
+#if VM_PHYSSEG_MAX > 1
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ /* Should return a valid handle */
+ ATF_REQUIRE(uvm_physseg_valid_p(upm));
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ /* After the second call two segments should exist */
+ ATF_CHECK_EQ(2, uvm_physseg_get_entries());
+#endif
+}
+
+ATF_TC(uvm_page_physload_postboot);
+ATF_TC_HEAD(uvm_page_physload_postboot, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physload() \
+ panic()s in a post boot scenario.");
+}
+ATF_TC_BODY(uvm_page_physload_postboot, tc)
+{
+ uvm_physseg_t upm;
+
+ psize_t npages1 = (VALID_END_PFN_1 - VALID_START_PFN_1);
+ psize_t npages2 = (VALID_END_PFN_2 - VALID_START_PFN_2);
+
+ struct vm_page *slab = malloc(sizeof(struct vm_page) * (npages1 + npages2));
+
+ setup();
+
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ /* Should return a valid handle */
+ ATF_REQUIRE(uvm_physseg_valid_p(upm));
+
+ /* No pages should be allocated yet */
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ /* After the first call one segment should exist */
+ ATF_CHECK_EQ(1, uvm_physseg_get_entries());
+
+ /* Post boot: Fake all segments and pages accounted for. */
+ uvm_page_init_fake(slab, npages1 + npages2);
+
+ atf_tc_expect_signal(SIGABRT,
+ "uvm_page_physload() called post boot");
+
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ /* Should return a valid handle */
+ ATF_REQUIRE(uvm_physseg_valid_p(upm));
+
+ ATF_REQUIRE_EQ(npages1 + npages2, uvmexp.npages);
+
+ /* After the second call two segments should exist */
+ ATF_CHECK_EQ(2, uvm_physseg_get_entries());
+}
+
+ATF_TC(uvm_physseg_handle_immutable);
+ATF_TC_HEAD(uvm_physseg_handle_immutable, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the uvm_physseg_t handle is \
+ immutable.");
+}
+ATF_TC_BODY(uvm_physseg_handle_immutable, tc)
+{
+ uvm_physseg_t upm;
+
+ /* We insert the segments in out of order */
+
+ setup();
+
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID_EMPTY, uvm_physseg_get_prev(upm));
+
+ /* Insert more than one segment iff VM_PHYSSEG_MAX > 1 */
+#if VM_PHYSSEG_MAX > 1
+ uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ /* Fetch Previous, we inserted a lower value */
+ upm = uvm_physseg_get_prev(upm);
+
+#if !defined(UVM_HOTPLUG)
+ /*
+ * This test is going to fail for the Array Implementation but is
+ * expected to pass in the RB Tree implementation.
+ */
+ /* Failure can be expected iff there are more than one handles */
+ atf_tc_expect_fail("Mutable handle in static array impl.");
+#endif
+ ATF_CHECK(UVM_PHYSSEG_TYPE_INVALID_EMPTY != upm);
+ ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
+#endif
+}
+
+ATF_TC(uvm_physseg_seg_chomp_slab);
+ATF_TC_HEAD(uvm_physseg_seg_chomp_slab, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "The slab import code.()");
+
+}
+ATF_TC_BODY(uvm_physseg_seg_chomp_slab, tc)
+{
+ int err;
+ size_t i;
+ struct uvm_physseg *seg;
+ struct vm_page *slab, *pgs;
+ const size_t npages = UVM_PHYSSEG_BOOT_UNPLUG_MAX; /* Number of pages */
+
+ setup();
+
+ /* This is boot time */
+ slab = malloc(sizeof(struct vm_page) * npages * 2);
+
+ seg = uvm_physseg_alloc(sizeof(struct uvm_physseg));
+
+ uvm_physseg_seg_chomp_slab(PHYSSEG_NODE_TO_HANDLE(seg), slab, npages * 2);
+
+ /* Should be able to allocate two 128 * sizeof(*slab) */
+ ATF_REQUIRE_EQ(0, extent_alloc(seg->ext, sizeof(*slab), 1, 0, EX_BOUNDZERO, (void *)&pgs));
+ err = extent_free(seg->ext, (u_long) pgs, sizeof(*slab), EX_BOUNDZERO);
+
+#if VM_PHYSSEG_MAX == 1
+ /*
+ * free() needs an extra region descriptor, but we only have
+ * one! The classic alloc() at free() problem
+ */
+
+ ATF_REQUIRE_EQ(ENOMEM, err);
+#else
+ /* Try alloc/free at static time */
+ for (i = 0; i < npages; i++) {
+ ATF_REQUIRE_EQ(0, extent_alloc(seg->ext, sizeof(*slab), 1, 0, EX_BOUNDZERO, (void *)&pgs));
+ err = extent_free(seg->ext, (u_long) pgs, sizeof(*slab), EX_BOUNDZERO);
+ ATF_REQUIRE_EQ(0, err);
+ }
+#endif
+
+ /* Now setup post boot */
+ uvm.page_init_done = true;
+
+ uvm_physseg_seg_chomp_slab(PHYSSEG_NODE_TO_HANDLE(seg), slab, npages * 2);
+
+ /* Try alloc/free after uvm_page.c:uvm_page_init() as well */
+ for (i = 0; i < npages; i++) {
+ ATF_REQUIRE_EQ(0, extent_alloc(seg->ext, sizeof(*slab), 1, 0, EX_BOUNDZERO, (void *)&pgs));
+ err = extent_free(seg->ext, (u_long) pgs, sizeof(*slab), EX_BOUNDZERO);
+ ATF_REQUIRE_EQ(0, err);
+ }
+
+}
+
+ATF_TC(uvm_physseg_alloc_from_slab);
+ATF_TC_HEAD(uvm_physseg_alloc_from_slab, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "The slab alloc code.()");
+
+}
+ATF_TC_BODY(uvm_physseg_alloc_from_slab, tc)
+{
+ struct uvm_physseg *seg;
+ struct vm_page *slab, *pgs;
+ const size_t npages = UVM_PHYSSEG_BOOT_UNPLUG_MAX; /* Number of pages */
+
+ setup();
+
+ /* This is boot time */
+ slab = malloc(sizeof(struct vm_page) * npages * 2);
+
+ seg = uvm_physseg_alloc(sizeof(struct uvm_physseg));
+
+ uvm_physseg_seg_chomp_slab(PHYSSEG_NODE_TO_HANDLE(seg), slab, npages * 2);
+
+ pgs = uvm_physseg_seg_alloc_from_slab(PHYSSEG_NODE_TO_HANDLE(seg), npages);
+
+ ATF_REQUIRE(pgs != NULL);
+
+ /* Now setup post boot */
+ uvm.page_init_done = true;
+
+#if VM_PHYSSEG_MAX > 1
+ pgs = uvm_physseg_seg_alloc_from_slab(PHYSSEG_NODE_TO_HANDLE(seg), npages);
+ ATF_REQUIRE(pgs != NULL);
+#endif
+ atf_tc_expect_fail("alloc beyond extent");
+
+ pgs = uvm_physseg_seg_alloc_from_slab(PHYSSEG_NODE_TO_HANDLE(seg), npages);
+ ATF_REQUIRE(pgs != NULL);
+}
+
+ATF_TC(uvm_physseg_init_seg);
+ATF_TC_HEAD(uvm_physseg_init_seg, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if uvm_physseg_init_seg adds pages to"
+ "uvmexp.npages");
+}
+ATF_TC_BODY(uvm_physseg_init_seg, tc)
+{
+ struct uvm_physseg *seg;
+ struct vm_page *slab, *pgs;
+ const size_t npages = UVM_PHYSSEG_BOOT_UNPLUG_MAX; /* Number of pages */
+
+ setup();
+
+ /* This is boot time */
+ slab = malloc(sizeof(struct vm_page) * npages * 2);
+
+ seg = uvm_physseg_alloc(sizeof(struct uvm_physseg));
+
+ uvm_physseg_seg_chomp_slab(PHYSSEG_NODE_TO_HANDLE(seg), slab, npages * 2);
+
+ pgs = uvm_physseg_seg_alloc_from_slab(PHYSSEG_NODE_TO_HANDLE(seg), npages);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ seg->start = 0;
+ seg->end = npages;
+
+ seg->avail_start = 0;
+ seg->avail_end = npages;
+
+ uvm_physseg_init_seg(PHYSSEG_NODE_TO_HANDLE(seg), pgs);
+
+ ATF_REQUIRE_EQ(npages, uvmexp.npages);
+}
+
+#if 0
+ATF_TC(uvm_physseg_init_seg);
+ATF_TC_HEAD(uvm_physseg_init_seg, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physload() \
+ call works without a panic() after Segment is inited.");
+}
+ATF_TC_BODY(uvm_physseg_init_seg, tc)
+{
+ uvm_physseg_t upm;
+ psize_t npages = (VALID_END_PFN_1 - VALID_START_PFN_1);
+ struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_CHECK_EQ(0, uvmexp.npages);
+
+ /*
+ * Boot time physplug needs explicit external init,
+ * Duplicate what uvm_page.c:uvm_page_init() does.
+ * Note: not everything uvm_page_init() does gets done here.
+ * Read the source.
+ */
+ /* suck in backing slab, initialise extent. */
+ uvm_physseg_seg_chomp_slab(upm, pgs, npages);
+
+ /*
+ * Actual pgs[] allocation, from extent.
+ */
+ uvm_physseg_alloc_from_slab(upm, npages);
+
+ /* Now we initialize the segment */
+ uvm_physseg_init_seg(upm, pgs);
+
+ /* Done with boot simulation */
+ extent_init();
+ uvm.page_init_done = true;
+
+ /* We have total memory of 1MB */
+ ATF_CHECK_EQ(PAGE_COUNT_1M, uvmexp.npages);
+
+ upm =uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ /* We added another 1MB so PAGE_COUNT_1M + PAGE_COUNT_1M */
+ ATF_CHECK_EQ(PAGE_COUNT_1M + PAGE_COUNT_1M, uvmexp.npages);
+
+}
+#endif
+
+ATF_TC(uvm_physseg_get_start);
+ATF_TC_HEAD(uvm_physseg_get_start, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the start PFN is returned \
+ correctly from a segment created via uvm_page_physload().");
+}
+ATF_TC_BODY(uvm_physseg_get_start, tc)
+{
+ uvm_physseg_t upm;
+
+ /* Fake early boot */
+ setup();
+
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
+#endif
+}
+
+ATF_TC(uvm_physseg_get_start_invalid);
+ATF_TC_HEAD(uvm_physseg_get_start_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
+ correctly when uvm_physseg_get_start() is called with invalid \
+ parameter values.");
+}
+ATF_TC_BODY(uvm_physseg_get_start_invalid, tc)
+{
+ /* Check for pgs == NULL */
+ setup();
+ uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ /* Force other check conditions */
+ uvm.page_init_done = true;
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(true, uvm.page_init_done);
+
+ /* Invalid uvm_physseg_t */
+ ATF_CHECK_EQ((paddr_t) -1,
+ uvm_physseg_get_start(UVM_PHYSSEG_TYPE_INVALID));
+}
+
+ATF_TC(uvm_physseg_get_end);
+ATF_TC_HEAD(uvm_physseg_get_end, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the end PFN is returned \
+ correctly from a segment created via uvm_page_physload().");
+}
+ATF_TC_BODY(uvm_physseg_get_end, tc)
+{
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
+#endif
+}
+
+ATF_TC(uvm_physseg_get_end_invalid);
+ATF_TC_HEAD(uvm_physseg_get_end_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
+ correctly when uvm_physseg_get_end() is called with invalid \
+ parameter values.");
+}
+ATF_TC_BODY(uvm_physseg_get_end_invalid, tc)
+{
+ /* Check for pgs == NULL */
+ setup();
+ uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ /* Force other check conditions */
+ uvm.page_init_done = true;
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(true, uvm.page_init_done);
+
+ /* Invalid uvm_physseg_t */
+ ATF_CHECK_EQ((paddr_t) -1,
+ uvm_physseg_get_end(UVM_PHYSSEG_TYPE_INVALID));
+}
+
+ATF_TC(uvm_physseg_get_avail_start);
+ATF_TC_HEAD(uvm_physseg_get_avail_start, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the avail_start PFN is \
+ returned correctly from a segment created via uvm_page_physload().");
+}
+ATF_TC_BODY(uvm_physseg_get_avail_start, tc)
+{
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_1, uvm_physseg_get_avail_start(upm));
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2, uvm_physseg_get_avail_start(upm));
+#endif
+}
+
+ATF_TC(uvm_physseg_get_avail_start_invalid);
+ATF_TC_HEAD(uvm_physseg_get_avail_start_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
+ correctly when uvm_physseg_get_avail_start() is called with invalid\
+ parameter values.");
+}
+ATF_TC_BODY(uvm_physseg_get_avail_start_invalid, tc)
+{
+ /* Check for pgs == NULL */
+ setup();
+ uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ /* Force other check conditions */
+ uvm.page_init_done = true;
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(true, uvm.page_init_done);
+
+ /* Invalid uvm_physseg_t */
+ ATF_CHECK_EQ((paddr_t) -1,
+ uvm_physseg_get_avail_start(UVM_PHYSSEG_TYPE_INVALID));
+}
+
+ATF_TC(uvm_physseg_get_avail_end);
+ATF_TC_HEAD(uvm_physseg_get_avail_end, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the avail_end PFN is \
+ returned correctly from a segment created via uvm_page_physload().");
+}
+ATF_TC_BODY(uvm_physseg_get_avail_end, tc)
+{
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_1, uvm_physseg_get_avail_end(upm));
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
+#endif
+}
+
+ATF_TC(uvm_physseg_get_avail_end_invalid);
+ATF_TC_HEAD(uvm_physseg_get_avail_end_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
+ correctly when uvm_physseg_get_avail_end() is called with invalid\
+ parameter values.");
+}
+ATF_TC_BODY(uvm_physseg_get_avail_end_invalid, tc)
+{
+ /* Check for pgs == NULL */
+ setup();
+ uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ /* Force other check conditions */
+ uvm.page_init_done = true;
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(true, uvm.page_init_done);
+
+ /* Invalid uvm_physseg_t */
+ ATF_CHECK_EQ((paddr_t) -1,
+ uvm_physseg_get_avail_end(UVM_PHYSSEG_TYPE_INVALID));
+}
+
+ATF_TC(uvm_physseg_get_next);
+ATF_TC_HEAD(uvm_physseg_get_next, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the pointer values for next \
+ segment using the uvm_physseg_get_next() call.");
+}
+ATF_TC_BODY(uvm_physseg_get_next, tc)
+{
+ uvm_physseg_t upm;
+#if VM_PHYSSEG_MAX > 1
+ uvm_physseg_t upm_next;
+#endif
+
+ /* We insert the segments in ascending order */
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID_OVERFLOW,
+ uvm_physseg_get_next(upm));
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ upm_next = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ upm = uvm_physseg_get_next(upm); /* Fetch Next */
+
+ ATF_CHECK_EQ(upm_next, upm);
+ ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
+#endif
+
+ /* This test will be triggered only if there are 3 or more segments. */
+#if VM_PHYSSEG_MAX > 2
+ upm_next = uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
+ VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(3, uvm_physseg_get_entries());
+
+ upm = uvm_physseg_get_next(upm); /* Fetch Next */
+
+ ATF_CHECK_EQ(upm_next, upm);
+ ATF_CHECK_EQ(VALID_START_PFN_3, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_3, uvm_physseg_get_end(upm));
+#endif
+}
+
+ATF_TC(uvm_physseg_get_next_invalid);
+ATF_TC_HEAD(uvm_physseg_get_next_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
+ correctly when uvm_physseg_get_next() is called with invalid \
+ parameter values.");
+}
+ATF_TC_BODY(uvm_physseg_get_next_invalid, tc)
+{
+ uvm_physseg_t upm = UVM_PHYSSEG_TYPE_INVALID;
+
+ ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID, uvm_physseg_get_next(upm));
+}
+
+ATF_TC(uvm_physseg_get_prev);
+ATF_TC_HEAD(uvm_physseg_get_prev, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the pointer values for previous \
+ segment using the uvm_physseg_get_prev() call.");
+}
+ATF_TC_BODY(uvm_physseg_get_prev, tc)
+{
+#if VM_PHYSSEG_MAX > 1
+ uvm_physseg_t upm;
+#endif
+ uvm_physseg_t upm_prev;
+
+
+ setup();
+ upm_prev = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID_EMPTY,
+ uvm_physseg_get_prev(upm_prev));
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ /* Fetch Previous, we inserted a lower value */
+ upm = uvm_physseg_get_prev(upm);
+
+ ATF_CHECK_EQ(upm_prev, upm);
+ ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
+#endif
+
+ /* This test will be triggered only if there are 3 or more segments. */
+#if VM_PHYSSEG_MAX > 2
+ uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
+ VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(3, uvm_physseg_get_entries());
+
+ /*
+ * This will return a UVM_PHYSSEG_TYPE_INVALID_EMPTY we are at the
+ * lowest
+ */
+ upm = uvm_physseg_get_prev(upm);
+
+ ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID_EMPTY, upm);
+#endif
+}
+
+ATF_TC(uvm_physseg_get_prev_invalid);
+ATF_TC_HEAD(uvm_physseg_get_prev_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
+ correctly when uvm_physseg_get_prev() is called with invalid \
+ parameter values.");
+}
+ATF_TC_BODY(uvm_physseg_get_prev_invalid, tc)
+{
+ uvm_physseg_t upm = UVM_PHYSSEG_TYPE_INVALID;
+
+ ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID, uvm_physseg_get_prev(upm));
+}
+
+ATF_TC(uvm_physseg_get_first);
+ATF_TC_HEAD(uvm_physseg_get_first, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the pointer values for first \
+ segment (lowest node) using the uvm_physseg_get_first() call.");
+}
+ATF_TC_BODY(uvm_physseg_get_first, tc)
+{
+ uvm_physseg_t upm = UVM_PHYSSEG_TYPE_INVALID_EMPTY;
+ uvm_physseg_t upm_first;
+
+ /* Fake early boot */
+ setup();
+
+ /* No nodes exist */
+ ATF_CHECK_EQ(upm, uvm_physseg_get_first());
+
+ upm_first = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ /* Pointer to first should be the least valued node */
+ upm = uvm_physseg_get_first();
+ ATF_CHECK_EQ(upm_first, upm);
+ ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2, uvm_physseg_get_avail_start(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ /* Insert a node of lesser value */
+ upm_first = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_CHECK_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ /* Pointer to first should be the least valued node */
+ upm = uvm_physseg_get_first();
+ ATF_CHECK_EQ(upm_first, upm);
+ ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_1, uvm_physseg_get_avail_start(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_1, uvm_physseg_get_avail_end(upm));
+#endif
+
+ /* This test will be triggered only if there are 3 or more segments. */
+#if VM_PHYSSEG_MAX > 2
+ /* Insert a node of higher value */
+ upm_first =uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
+ VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_DEFAULT);
+
+ ATF_CHECK_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(3, uvm_physseg_get_entries());
+
+ /* Pointer to first should be the least valued node */
+ upm = uvm_physseg_get_first();
+ ATF_CHECK(upm_first != upm);
+ ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_1, uvm_physseg_get_avail_start(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_1, uvm_physseg_get_avail_end(upm));
+#endif
+}
+
+ATF_TC(uvm_physseg_get_last);
+ATF_TC_HEAD(uvm_physseg_get_last, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the pointer values for last \
+ segment using the uvm_physseg_get_last() call.");
+}
+ATF_TC_BODY(uvm_physseg_get_last, tc)
+{
+ uvm_physseg_t upm = UVM_PHYSSEG_TYPE_INVALID_EMPTY;
+ uvm_physseg_t upm_last;
+
+ setup();
+
+ /* No nodes exist */
+ ATF_CHECK_EQ(upm, uvm_physseg_get_last());
+
+ upm_last = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ /* Pointer to last should be the most valued node */
+ upm = uvm_physseg_get_last();
+ ATF_CHECK_EQ(upm_last, upm);
+ ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_1, uvm_physseg_get_avail_start(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_1, uvm_physseg_get_avail_end(upm));
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ /* Insert node of greater value */
+ upm_last = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ /* Pointer to last should be the most valued node */
+ upm = uvm_physseg_get_last();
+ ATF_CHECK_EQ(upm_last, upm);
+ ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2, uvm_physseg_get_avail_start(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
+#endif
+
+ /* This test will be triggered only if there are 3 or more segments. */
+#if VM_PHYSSEG_MAX > 2
+ /* Insert node of greater value */
+ upm_last = uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
+ VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(3, uvm_physseg_get_entries());
+
+ /* Pointer to last should be the most valued node */
+ upm = uvm_physseg_get_last();
+ ATF_CHECK_EQ(upm_last, upm);
+ ATF_CHECK_EQ(VALID_START_PFN_3, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_3, uvm_physseg_get_end(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_3, uvm_physseg_get_avail_start(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_3, uvm_physseg_get_avail_end(upm));
+#endif
+}
+
+ATF_TC(uvm_physseg_valid);
+ATF_TC_HEAD(uvm_physseg_valid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the pointer value for current \
+ segment is valid using the uvm_physseg_valid_p() call.");
+}
+ATF_TC_BODY(uvm_physseg_valid, tc)
+{
+ psize_t npages = (VALID_END_PFN_1 - VALID_START_PFN_1);
+
+ struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
+
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ uvm_physseg_init_seg(upm, pgs);
+
+ ATF_REQUIRE_EQ(PAGE_COUNT_1M, uvmexp.npages);
+
+ ATF_CHECK_EQ(true, uvm_physseg_valid_p(upm));
+}
+
+ATF_TC(uvm_physseg_valid_invalid);
+ATF_TC_HEAD(uvm_physseg_valid_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the pointer value for current \
+ segment is invalid using the uvm_physseg_valid_p() call.");
+}
+ATF_TC_BODY(uvm_physseg_valid_invalid, tc)
+{
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ /* Force other check conditions */
+ uvm.page_init_done = true;
+
+ ATF_REQUIRE_EQ(true, uvm.page_init_done);
+
+ /* Invalid uvm_physseg_t */
+ ATF_CHECK_EQ(false, uvm_physseg_valid_p(UVM_PHYSSEG_TYPE_INVALID));
+
+ /*
+ * Without any pages initialized for segment, it is considered
+ * invalid
+ */
+ ATF_CHECK_EQ(false, uvm_physseg_valid_p(upm));
+}
+
+ATF_TC(uvm_physseg_get_highest);
+ATF_TC_HEAD(uvm_physseg_get_highest, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the returned PFN matches \
+ the highest PFN in use by the system.");
+}
+ATF_TC_BODY(uvm_physseg_get_highest, tc)
+{
+ setup();
+ uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ /* Only one segment so highest is the current */
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_1 - 1, uvm_physseg_get_highest_frame());
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
+ VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_DEFAULT);
+
+ /* PFN_3 > PFN_1 */
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_3 - 1, uvm_physseg_get_highest_frame());
+#endif
+
+ /* This test will be triggered only if there are 3 or more segments. */
+#if VM_PHYSSEG_MAX > 2
+ uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ /* PFN_3 > PFN_2 */
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_3 - 1, uvm_physseg_get_highest_frame());
+#endif
+}
+
+ATF_TC(uvm_physseg_get_free_list);
+ATF_TC_HEAD(uvm_physseg_get_free_list, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the returned Free List type \
+ of a segment matches the one returned from \
+ uvm_physseg_get_free_list() call.");
+}
+ATF_TC_BODY(uvm_physseg_get_free_list, tc)
+{
+ uvm_physseg_t upm;
+
+ /* Fake early boot */
+ setup();
+
+ /* Insertions are made in ascending order */
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_CHECK_EQ(VM_FREELIST_DEFAULT, uvm_physseg_get_free_list(upm));
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_FIRST16);
+
+ ATF_CHECK_EQ(VM_FREELIST_FIRST16, uvm_physseg_get_free_list(upm));
+#endif
+
+ /* This test will be triggered only if there are 3 or more segments. */
+#if VM_PHYSSEG_MAX > 2
+ upm = uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
+ VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_FIRST1G);
+
+ ATF_CHECK_EQ(VM_FREELIST_FIRST1G, uvm_physseg_get_free_list(upm));
+#endif
+}
+
+ATF_TC(uvm_physseg_get_start_hint);
+ATF_TC_HEAD(uvm_physseg_get_start_hint, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the returned start_hint value \
+ of a segment matches the one returned from \
+ uvm_physseg_get_start_hint() call.");
+}
+ATF_TC_BODY(uvm_physseg_get_start_hint, tc)
+{
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ /* Will be Zero since no specific value is set during init */
+ ATF_CHECK_EQ(0, uvm_physseg_get_start_hint(upm));
+}
+
+ATF_TC(uvm_physseg_set_start_hint);
+ATF_TC_HEAD(uvm_physseg_set_start_hint, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the returned start_hint value \
+ of a segment matches the one set by the \
+ uvm_physseg_set_start_hint() call.");
+}
+ATF_TC_BODY(uvm_physseg_set_start_hint, tc)
+{
+ psize_t npages = (VALID_END_PFN_1 - VALID_START_PFN_1);
+
+ struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
+
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ uvm_physseg_init_seg(upm, pgs);
+
+ ATF_CHECK_EQ(true, uvm_physseg_set_start_hint(upm, atop(128)));
+
+ /* Will be atop(128) since no specific value is set above */
+ ATF_CHECK_EQ(atop(128), uvm_physseg_get_start_hint(upm));
+}
+
+ATF_TC(uvm_physseg_set_start_hint_invalid);
+ATF_TC_HEAD(uvm_physseg_set_start_hint_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the returned value is false \
+ when an invalid segment matches the one trying to set by the \
+ uvm_physseg_set_start_hint() call.");
+}
+ATF_TC_BODY(uvm_physseg_set_start_hint_invalid, tc)
+{
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ /* Force other check conditions */
+ uvm.page_init_done = true;
+
+ ATF_REQUIRE_EQ(true, uvm.page_init_done);
+
+ ATF_CHECK_EQ(false, uvm_physseg_set_start_hint(upm, atop(128)));
+
+ /*
+ * Will be Zero since no specific value is set after the init
+ * due to failure
+ */
+ atf_tc_expect_signal(SIGABRT, "invalid uvm_physseg_t handle");
+
+ ATF_CHECK_EQ(0, uvm_physseg_get_start_hint(upm));
+}
+
+ATF_TC(uvm_physseg_get_pg);
+ATF_TC_HEAD(uvm_physseg_get_pg, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the returned vm_page struct \
+ is correct when fetched by uvm_physseg_get_pg() call.");
+}
+ATF_TC_BODY(uvm_physseg_get_pg, tc)
+{
+ psize_t npages = (VALID_END_PFN_1 - VALID_START_PFN_1);
+
+ struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
+
+ struct vm_page *extracted_pg = NULL;
+
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ /* Now we initialize the segment */
+ uvm_physseg_init_seg(upm, pgs);
+
+ ATF_REQUIRE_EQ(PAGE_COUNT_1M, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(NULL, extracted_pg);
+
+ /* Try fetching the 5th Page in the Segment */
+ extracted_pg = uvm_physseg_get_pg(upm, 5);
+
+ /* Values of phys_addr is n * PAGE_SIZE where n is the page number */
+ ATF_CHECK_EQ(5 * PAGE_SIZE, extracted_pg->phys_addr);
+
+ /* Try fetching the 113th Page in the Segment */
+ extracted_pg = uvm_physseg_get_pg(upm, 113);
+
+ ATF_CHECK_EQ(113 * PAGE_SIZE, extracted_pg->phys_addr);
+}
+
+#ifdef __HAVE_PMAP_PHYSSEG
+ATF_TC(uvm_physseg_get_pmseg);
+ATF_TC_HEAD(uvm_physseg_get_pmseg, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the returned pmap_physseg \
+ struct is correct when fetched by uvm_physseg_get_pmseg() call.");
+}
+ATF_TC_BODY(uvm_physseg_get_pmseg, tc)
+{
+ psize_t npages = (VALID_END_PFN_1 - VALID_START_PFN_1);
+
+ struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
+
+ struct pmap_physseg pmseg = { true };
+
+ struct pmap_physseg *extracted_pmseg = NULL;
+
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ /* Now we initialize the segment */
+ uvm_physseg_init_seg(upm, pgs);
+
+ ATF_REQUIRE_EQ(PAGE_COUNT_1M, uvmexp.npages);
+
+ ATF_REQUIRE_EQ(NULL, extracted_pmseg);
+
+ ATF_REQUIRE_EQ(true, pmseg.dummy_variable);
+
+ /* Extract the current pmseg */
+ extracted_pmseg = uvm_physseg_get_pmseg(upm);
+
+ /*
+ * We can only check if it is not NULL
+ * We do not know the value it contains
+ */
+ ATF_CHECK(NULL != extracted_pmseg);
+
+ extracted_pmseg->dummy_variable = pmseg.dummy_variable;
+
+ /* Invert value to ensure test integrity */
+ pmseg.dummy_variable = false;
+
+ ATF_REQUIRE_EQ(false, pmseg.dummy_variable);
+
+ extracted_pmseg = uvm_physseg_get_pmseg(upm);
+
+ ATF_CHECK(NULL != extracted_pmseg);
+
+ ATF_CHECK_EQ(true, extracted_pmseg->dummy_variable);
+}
+#endif
+
+ATF_TC(vm_physseg_find);
+ATF_TC_HEAD(vm_physseg_find, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the returned segment number \
+ is correct when an PFN is passed into uvm_physseg_find() call. \
+ In addition to this the offset of the PFN from the start of \
+ segment is also set if the parameter is passed in as not NULL.");
+}
+ATF_TC_BODY(vm_physseg_find, tc)
+{
+ psize_t offset = (psize_t) -1;
+
+ uvm_physseg_t upm_first, result;
+#if VM_PHYSSEG_MAX > 1
+ uvm_physseg_t upm_second;
+#endif
+
+ setup();
+
+ upm_first = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ upm_second = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+#endif
+
+ /* Under ONE_MEGABYTE is segment upm_first */
+ result = uvm_physseg_find(atop(ONE_MEGABYTE - 1024), NULL);
+ ATF_CHECK_EQ(upm_first, result);
+ ATF_CHECK_EQ(uvm_physseg_get_start(upm_first),
+ uvm_physseg_get_start(result));
+ ATF_CHECK_EQ(uvm_physseg_get_end(upm_first),
+ uvm_physseg_get_end(result));
+ ATF_CHECK_EQ(uvm_physseg_get_avail_start(upm_first),
+ uvm_physseg_get_avail_start(result));
+ ATF_CHECK_EQ(uvm_physseg_get_avail_end(upm_first),
+ uvm_physseg_get_avail_end(result));
+
+ ATF_REQUIRE_EQ((psize_t) -1, offset);
+
+ /* This test will be triggered only if there are 2 or more segments. */
+#if VM_PHYSSEG_MAX > 1
+ /* Over ONE_MEGABYTE is segment upm_second */
+ result = uvm_physseg_find(atop(ONE_MEGABYTE + 8192), &offset);
+ ATF_CHECK_EQ(upm_second, result);
+ ATF_CHECK_EQ(uvm_physseg_get_start(upm_second),
+ uvm_physseg_get_start(result));
+ ATF_CHECK_EQ(uvm_physseg_get_end(upm_second),
+ uvm_physseg_get_end(result));
+ ATF_CHECK_EQ(uvm_physseg_get_avail_start(upm_second),
+ uvm_physseg_get_avail_start(result));
+ ATF_CHECK_EQ(uvm_physseg_get_avail_end(upm_second),
+ uvm_physseg_get_avail_end(result));
+
+ /* Offset is calculated based on PAGE_SIZE */
+ /* atop(ONE_MEGABYTE + (2 * PAGE_SIZE)) - VALID_START_PFN1 = 2 */
+ ATF_CHECK_EQ(2, offset);
+#else
+ /* Under ONE_MEGABYTE is segment upm_first */
+ result = uvm_physseg_find(atop(ONE_MEGABYTE - 12288), &offset);
+ ATF_CHECK_EQ(upm_first, result);
+ ATF_CHECK_EQ(uvm_physseg_get_start(upm_first),
+ uvm_physseg_get_start(result));
+ ATF_CHECK_EQ(uvm_physseg_get_end(upm_first),
+ uvm_physseg_get_end(result));
+ ATF_CHECK_EQ(uvm_physseg_get_avail_start(upm_first),
+ uvm_physseg_get_avail_start(result));
+ ATF_CHECK_EQ(uvm_physseg_get_avail_end(upm_first),
+ uvm_physseg_get_avail_end(result));
+
+ /* Offset is calculated based on PAGE_SIZE */
+ /* atop(ONE_MEGABYTE - (3 * PAGE_SIZE)) - VALID_START_PFN1 = 253 */
+ ATF_CHECK_EQ(253, offset);
+#endif
+}
+
+ATF_TC(vm_physseg_find_invalid);
+ATF_TC_HEAD(vm_physseg_find_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the returned segment number \
+ is (paddr_t) -1 when a non existant PFN is passed into \
+ uvm_physseg_find() call.");
+}
+ATF_TC_BODY(vm_physseg_find_invalid, tc)
+{
+ psize_t offset = (psize_t) -1;
+
+ setup();
+ uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ /* No segments over 3 MB exists at the moment */
+ ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID,
+ uvm_physseg_find(atop(ONE_MEGABYTE * 3), NULL));
+
+ ATF_REQUIRE_EQ((psize_t) -1, offset);
+
+ /* No segments over 3 MB exists at the moment */
+ ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID,
+ uvm_physseg_find(atop(ONE_MEGABYTE * 3), &offset));
+
+ ATF_CHECK_EQ((psize_t) -1, offset);
+}
+
+ATF_TC(uvm_page_physunload_start);
+ATF_TC_HEAD(uvm_page_physunload_start, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physunload()\
+ call works without a panic(). Unloads from Start of the segment.");
+}
+ATF_TC_BODY(uvm_page_physunload_start, tc)
+{
+ /*
+ * Would uvmexp.npages reduce everytime an uvm_page_physunload is called?
+ */
+ psize_t npages = (VALID_END_PFN_2 - VALID_START_PFN_2);
+
+ struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
+
+ paddr_t p = 0;
+
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ uvm_physseg_init_seg(upm, pgs);
+
+ ATF_CHECK_EQ(true, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
+
+ /*
+ * When called for first time, uvm_page_physload() removes the first PFN
+ *
+ * New avail start will be VALID_AVAIL_START_PFN_2 + 1
+ */
+ ATF_CHECK_EQ(VALID_START_PFN_2, atop(p));
+
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2 + 1,
+ uvm_physseg_get_avail_start(upm));
+
+ ATF_CHECK_EQ(VALID_START_PFN_2 + 1, uvm_physseg_get_start(upm));
+
+ /* Rest of the stuff should remain the same */
+ ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
+}
+
+ATF_TC(uvm_page_physunload_end);
+ATF_TC_HEAD(uvm_page_physunload_end, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physunload()\
+ call works without a panic(). Unloads from End of the segment.");
+}
+ATF_TC_BODY(uvm_page_physunload_end, tc)
+{
+ /*
+ * Would uvmexp.npages reduce everytime an uvm_page_physunload is called?
+ */
+ paddr_t p = 0;
+
+ uvm_physseg_t upm;
+
+ setup();
+ /* Note: start != avail_start to remove from end. */
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2 + 1, VALID_AVAIL_END_PFN_2,
+ VM_FREELIST_DEFAULT);
+
+ p = 0;
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE(
+ uvm_physseg_get_avail_start(upm) != uvm_physseg_get_start(upm));
+
+ ATF_CHECK_EQ(true, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
+
+ /*
+ * Remember if X is the upper limit the actual valid pointer is X - 1
+ *
+ * For example if 256 is the upper limit for 1MB memory, last valid
+ * pointer is 256 - 1 = 255
+ */
+
+ ATF_CHECK_EQ(VALID_END_PFN_2 - 1, atop(p));
+
+ /*
+ * When called for second time, uvm_page_physload() removes the last PFN
+ *
+ * New avail end will be VALID_AVAIL_END_PFN_2 - 1
+ * New end will be VALID_AVAIL_PFN_2 - 1
+ */
+
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2 - 1, uvm_physseg_get_avail_end(upm));
+
+ ATF_CHECK_EQ(VALID_END_PFN_2 - 1, uvm_physseg_get_end(upm));
+
+ /* Rest of the stuff should remain the same */
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2 + 1,
+ uvm_physseg_get_avail_start(upm));
+ ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
+}
+
+ATF_TC(uvm_page_physunload_none);
+ATF_TC_HEAD(uvm_page_physunload_none, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physunload()\
+ call works without a panic(). Does not unload from start or end \
+ because of non-aligned start / avail_start and end / avail_end \
+ respectively.");
+}
+ATF_TC_BODY(uvm_page_physunload_none, tc)
+{
+ psize_t npages = (VALID_END_PFN_2 - VALID_START_PFN_2);
+
+ struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
+
+ paddr_t p = 0;
+
+ uvm_physseg_t upm;
+
+ setup();
+ /*
+ * Note: start != avail_start and end != avail_end.
+ *
+ * This prevents any unload from occuring.
+ */
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2 + 1, VALID_AVAIL_END_PFN_2 - 1,
+ VM_FREELIST_DEFAULT);
+
+ p = 0;
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_REQUIRE(
+ uvm_physseg_get_avail_start(upm) != uvm_physseg_get_start(upm));
+
+ uvm_physseg_init_seg(upm, pgs);
+
+ ATF_CHECK_EQ(false, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
+
+ /* uvm_page_physload() will no longer unload memory */
+ ATF_CHECK_EQ(0, p);
+
+ /* Rest of the stuff should remain the same */
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2 + 1,
+ uvm_physseg_get_avail_start(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2 - 1,
+ uvm_physseg_get_avail_end(upm));
+ ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
+}
+
+ATF_TC(uvm_page_physunload_delete_start);
+ATF_TC_HEAD(uvm_page_physunload_delete_start, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the uvm_page_physunload() \
+ works when the segment gets small enough to be deleted scenario. \
+ NOTE: This one works deletes from start.");
+}
+ATF_TC_BODY(uvm_page_physunload_delete_start, tc)
+{
+ /*
+ * Would uvmexp.npages reduce everytime an uvm_page_physunload is called?
+ */
+ paddr_t p = 0;
+
+ uvm_physseg_t upm;
+
+ setup();
+
+ /*
+ * Setup the Nuke from Starting point
+ */
+
+ upm = uvm_page_physload(VALID_END_PFN_1 - 1, VALID_END_PFN_1,
+ VALID_AVAIL_END_PFN_1 - 1, VALID_AVAIL_END_PFN_1,
+ VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ /* Insert more than one segment iff VM_PHYSSEG_MAX > 1 */
+#if VM_PHYSSEG_MAX > 1
+ uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+#endif
+
+#if VM_PHYSSEG_MAX == 1
+ atf_tc_expect_signal(SIGABRT,
+ "cannot uvm_page_physunload() the last segment");
+#endif
+
+ ATF_CHECK_EQ(true, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
+
+ ATF_CHECK_EQ(VALID_END_PFN_1 - 1, atop(p));
+
+ ATF_CHECK_EQ(1, uvm_physseg_get_entries());
+
+ /* The only node now is the one we inserted second. */
+ upm = uvm_physseg_get_first();
+
+ ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2, uvm_physseg_get_avail_start(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
+}
+
+ATF_TC(uvm_page_physunload_delete_end);
+ATF_TC_HEAD(uvm_page_physunload_delete_end, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the uvm_page_physunload() \
+ works when the segment gets small enough to be deleted scenario. \
+ NOTE: This one works deletes from end.");
+}
+ATF_TC_BODY(uvm_page_physunload_delete_end, tc)
+{
+ /*
+ * Would uvmexp.npages reduce everytime an uvm_page_physunload is called?
+ */
+
+ paddr_t p = 0;
+
+ uvm_physseg_t upm;
+
+ setup();
+
+ /*
+ * Setup the Nuke from Ending point
+ */
+
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_START_PFN_1 + 2,
+ VALID_AVAIL_START_PFN_1 + 1, VALID_AVAIL_START_PFN_1 + 2,
+ VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ /* Insert more than one segment iff VM_PHYSSEG_MAX > 1 */
+#if VM_PHYSSEG_MAX > 1
+ uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+#endif
+
+#if VM_PHYSSEG_MAX == 1
+ atf_tc_expect_signal(SIGABRT,
+ "cannot uvm_page_physunload() the last segment");
+#endif
+
+ ATF_CHECK_EQ(true, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
+
+ p = 0;
+
+ ATF_CHECK_EQ(true, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
+
+ ATF_CHECK_EQ(VALID_START_PFN_1 + 2, atop(p));
+
+ ATF_CHECK_EQ(1, uvm_physseg_get_entries());
+
+ /* The only node now is the one we inserted second. */
+ upm = uvm_physseg_get_first();
+
+ ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
+ ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2, uvm_physseg_get_avail_start(upm));
+ ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
+}
+
+ATF_TC(uvm_page_physunload_invalid);
+ATF_TC_HEAD(uvm_page_physunload_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the uvm_page_physunload() \
+ fails when then Free list does not match.");
+}
+ATF_TC_BODY(uvm_page_physunload_invalid, tc)
+{
+ psize_t npages = (VALID_END_PFN_2 - VALID_START_PFN_2);
+
+ struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
+
+ paddr_t p = 0;
+
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ uvm_physseg_init_seg(upm, pgs);
+
+ ATF_CHECK_EQ(false, uvm_page_physunload(upm, VM_FREELIST_FIRST4G, &p));
+}
+
+ATF_TC(uvm_page_physunload_force);
+ATF_TC_HEAD(uvm_page_physunload_force, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the basic \
+ uvm_page_physunload_force() including delete works without.");
+}
+ATF_TC_BODY(uvm_page_physunload_force, tc)
+{
+ /*
+ * Would uvmexp.npages reduce everytime an uvm_page_physunload is called?
+ */
+ paddr_t p = 0;
+
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
+ VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ /* Insert more than one segment iff VM_PHYSSEG_MAX > 1 */
+#if VM_PHYSSEG_MAX > 1
+ /*
+ * We have couple of physloads done this is bacause of the fact that if
+ * we physunload all the PFs from a given range and we have only one
+ * segment in total a panic() is called
+ */
+ uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
+ VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+#endif
+
+#if VM_PHYSSEG_MAX == 1
+ atf_tc_expect_signal(SIGABRT,
+ "cannot uvm_page_physunload() the last segment");
+#endif
+
+ ATF_REQUIRE_EQ(VALID_AVAIL_START_PFN_1,
+ uvm_physseg_get_avail_start(upm));
+
+ for(paddr_t i = VALID_AVAIL_START_PFN_1;
+ i < VALID_AVAIL_END_PFN_1; i++) {
+ ATF_CHECK_EQ(true,
+ uvm_page_physunload_force(upm, VM_FREELIST_DEFAULT, &p));
+ ATF_CHECK_EQ(i, atop(p));
+
+ if(i + 1 < VALID_AVAIL_END_PFN_1)
+ ATF_CHECK_EQ(i + 1, uvm_physseg_get_avail_start(upm));
+ }
+
+ /*
+ * Now we try to retrieve the segment, which has been removed
+ * from the system through force unloading all the pages inside it.
+ */
+ upm = uvm_physseg_find(VALID_AVAIL_END_PFN_1 - 1, NULL);
+
+ /* It should no longer exist */
+ ATF_CHECK_EQ(NULL, upm);
+
+ ATF_CHECK_EQ(1, uvm_physseg_get_entries());
+}
+
+ATF_TC(uvm_page_physunload_force_invalid);
+ATF_TC_HEAD(uvm_page_physunload_force_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests if the invalid conditions for \
+ uvm_page_physunload_force_invalid().");
+}
+ATF_TC_BODY(uvm_page_physunload_force_invalid, tc)
+{
+ paddr_t p = 0;
+
+ uvm_physseg_t upm;
+
+ setup();
+ upm = uvm_page_physload(VALID_START_PFN_2, VALID_START_PFN_2+ 1,
+ VALID_START_PFN_2, VALID_START_PFN_2, VM_FREELIST_DEFAULT);
+
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ ATF_REQUIRE_EQ(0, uvmexp.npages);
+
+ ATF_CHECK_EQ(false,
+ uvm_page_physunload_force(upm, VM_FREELIST_DEFAULT, &p));
+
+ ATF_CHECK_EQ(0, p);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+#if defined(UVM_HOTPLUG)
+ /* Internal */
+ ATF_TP_ADD_TC(tp, uvm_physseg_alloc_atboot_mismatch);
+ ATF_TP_ADD_TC(tp, uvm_physseg_alloc_atboot_overrun);
+ ATF_TP_ADD_TC(tp, uvm_physseg_alloc_sanity);
+ ATF_TP_ADD_TC(tp, uvm_physseg_free_atboot_mismatch);
+ ATF_TP_ADD_TC(tp, uvm_physseg_free_sanity);
+#if VM_PHYSSEG_MAX > 1
+ ATF_TP_ADD_TC(tp, uvm_physseg_atboot_free_leak);
+#endif
+#endif /* UVM_HOTPLUG */
+
+ ATF_TP_ADD_TC(tp, uvm_physseg_plug);
+ ATF_TP_ADD_TC(tp, uvm_physseg_unplug);
+
+ /* Exported */
+ ATF_TP_ADD_TC(tp, uvm_physseg_init);
+ ATF_TP_ADD_TC(tp, uvm_page_physload_preload);
+ ATF_TP_ADD_TC(tp, uvm_page_physload_postboot);
+ ATF_TP_ADD_TC(tp, uvm_physseg_handle_immutable);
+ ATF_TP_ADD_TC(tp, uvm_physseg_seg_chomp_slab);
+ ATF_TP_ADD_TC(tp, uvm_physseg_alloc_from_slab);
+ ATF_TP_ADD_TC(tp, uvm_physseg_init_seg);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_start);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_start_invalid);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_end);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_end_invalid);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_avail_start);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_avail_start_invalid);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_avail_end);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_avail_end_invalid);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_next);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_next_invalid);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_prev);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_prev_invalid);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_first);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_last);
+ ATF_TP_ADD_TC(tp, uvm_physseg_valid);
+ ATF_TP_ADD_TC(tp, uvm_physseg_valid_invalid);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_highest);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_free_list);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_start_hint);
+ ATF_TP_ADD_TC(tp, uvm_physseg_set_start_hint);
+ ATF_TP_ADD_TC(tp, uvm_physseg_set_start_hint_invalid);
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_pg);
+
+#ifdef __HAVE_PMAP_PHYSSEG
+ ATF_TP_ADD_TC(tp, uvm_physseg_get_pmseg);
+#endif
+ ATF_TP_ADD_TC(tp, vm_physseg_find);
+ ATF_TP_ADD_TC(tp, vm_physseg_find_invalid);
+
+ ATF_TP_ADD_TC(tp, uvm_page_physunload_start);
+ ATF_TP_ADD_TC(tp, uvm_page_physunload_end);
+ ATF_TP_ADD_TC(tp, uvm_page_physunload_none);
+ ATF_TP_ADD_TC(tp, uvm_page_physunload_delete_start);
+ ATF_TP_ADD_TC(tp, uvm_page_physunload_delete_end);
+ ATF_TP_ADD_TC(tp, uvm_page_physunload_invalid);
+ ATF_TP_ADD_TC(tp, uvm_page_physunload_force);
+ ATF_TP_ADD_TC(tp, uvm_page_physunload_force_invalid);
+
+ return atf_no_error();
+}
diff --git a/sys/uvm/t_uvm_physseg_load.c b/sys/uvm/t_uvm_physseg_load.c
new file mode 100644
index 000000000000..a150f6976c7b
--- /dev/null
+++ b/sys/uvm/t_uvm_physseg_load.c
@@ -0,0 +1,740 @@
+/* $NetBSD: t_uvm_physseg_load.c,v 1.2 2016/12/22 08:15:20 cherry Exp $ */
+
+/*-
+ * Copyright (c) 2015, 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Santhosh N. Raju <santhosh.raju@gmail.com> and
+ * by Cherry G. Mathew
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_uvm_physseg_load.c,v 1.2 2016/12/22 08:15:20 cherry Exp $");
+
+/*
+ * If this line is commented out tests related touvm_physseg_get_pmseg()
+ * wont run.
+ *
+ * Have a look at machine/uvm_physseg.h for more details.
+ */
+#define __HAVE_PMAP_PHYSSEG
+
+/*
+ * This is a dummy struct used for testing purposes
+ *
+ * In reality this struct would exist in the MD part of the code residing in
+ * machines/vmparam.h
+ */
+
+#ifdef __HAVE_PMAP_PHYSSEG
+struct pmap_physseg {
+ int dummy_variable; /* Dummy variable use for testing */
+};
+#endif
+
+/* Testing API - assumes userland */
+/* Provide Kernel API equivalents */
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h> /* memset(3) et. al */
+#include <stdio.h> /* printf(3) */
+#include <stdlib.h> /* malloc(3) */
+#include <stdarg.h>
+#include <stddef.h>
+#include <time.h>
+
+#define PRIxPADDR "lx"
+#define PRIxPSIZE "lx"
+#define PRIuPSIZE "lu"
+#define PRIxVADDR "lx"
+#define PRIxVSIZE "lx"
+#define PRIuVSIZE "lu"
+
+#define UVM_HOTPLUG /* Enable hotplug with rbtree. */
+#define PMAP_STEAL_MEMORY
+#define DEBUG /* Enable debug functionality. */
+
+typedef unsigned long vaddr_t;
+typedef unsigned long paddr_t;
+typedef unsigned long psize_t;
+typedef unsigned long vsize_t;
+
+#include <uvm/uvm_physseg.h>
+#include <uvm/uvm_page.h>
+
+#ifndef DIAGNOSTIC
+#define KASSERTMSG(e, msg, ...) /* NOTHING */
+#define KASSERT(e) /* NOTHING */
+#else
+#define KASSERT(a) assert(a)
+#define KASSERTMSG(exp, ...) printf(__VA_ARGS__); assert((exp))
+#endif
+
+#define VM_PHYSSEG_STRAT VM_PSTRAT_BSEARCH
+
+#define VM_NFREELIST 4
+#define VM_FREELIST_DEFAULT 0
+#define VM_FREELIST_FIRST16 3
+#define VM_FREELIST_FIRST1G 2
+#define VM_FREELIST_FIRST4G 1
+
+/*
+ * Used in tests when Array implementation is tested
+ */
+#if !defined(VM_PHYSSEG_MAX)
+#define VM_PHYSSEG_MAX 32
+#endif
+
+#define PAGE_SIZE 4096
+#define PAGE_SHIFT 12
+#define atop(x) (((paddr_t)(x)) >> PAGE_SHIFT)
+
+#define mutex_enter(l)
+#define mutex_exit(l)
+
+#define _SYS_KMEM_H_ /* Disallow the real kmem API (see below) */
+/* free(p) XXX: pgs management need more thought */
+#define kmem_alloc(size, flags) malloc(size)
+#define kmem_zalloc(size, flags) malloc(size)
+#define kmem_free(p, size) free(p)
+
+psize_t physmem;
+
+struct uvmexp uvmexp; /* decl */
+
+/*
+ * uvm structure borrowed from uvm.h
+ *
+ * Remember this is a dummy structure used within the ATF Tests and
+ * uses only necessary fields from the original uvm struct.
+ * See uvm/uvm.h for the full struct.
+ */
+
+struct uvm {
+ /* vm_page related parameters */
+
+ bool page_init_done; /* TRUE if uvm_page_init() finished */
+} uvm;
+
+static void
+panic(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ printf("\n");
+ va_end(ap);
+ KASSERT(false);
+
+ /*NOTREACHED*/
+}
+
+static void
+uvm_pagefree(struct vm_page *pg)
+{
+ return;
+}
+
+#if defined(UVM_HOTPLUG)
+static void
+uvmpdpol_reinit(void)
+{
+ return;
+}
+#endif /* UVM_HOTPLUG */
+
+/* end - Provide Kernel API equivalents */
+
+#include "uvm/uvm_physseg.c"
+
+#include <atf-c.h>
+
+#define ONE_MEGABYTE 1024 * 1024
+
+/* Sample Page Frame Numbers */
+#define VALID_START_PFN_1 atop(0)
+#define VALID_END_PFN_1 atop(ONE_MEGABYTE)
+#define VALID_AVAIL_START_PFN_1 atop(0)
+#define VALID_AVAIL_END_PFN_1 atop(ONE_MEGABYTE)
+
+#define VALID_START_PFN_2 atop(ONE_MEGABYTE + 1)
+#define VALID_END_PFN_2 atop(ONE_MEGABYTE * 2)
+#define VALID_AVAIL_START_PFN_2 atop(ONE_MEGABYTE + 1)
+#define VALID_AVAIL_END_PFN_2 atop(ONE_MEGABYTE * 2)
+
+#define VALID_START_PFN_3 atop((ONE_MEGABYTE * 2) + 1)
+#define VALID_END_PFN_3 atop(ONE_MEGABYTE * 3)
+#define VALID_AVAIL_START_PFN_3 atop((ONE_MEGABYTE * 2) + 1)
+#define VALID_AVAIL_END_PFN_3 atop(ONE_MEGABYTE * 3)
+
+#define VALID_START_PFN_4 atop(ONE_MEGABYTE + 1)
+#define VALID_END_PFN_4 atop(ONE_MEGABYTE * 128)
+#define VALID_AVAIL_START_PFN_4 atop(ONE_MEGABYTE + 1)
+#define VALID_AVAIL_END_PFN_4 atop(ONE_MEGABYTE * 128)
+
+#define VALID_START_PFN_5 atop(ONE_MEGABYTE + 1)
+#define VALID_END_PFN_5 atop(ONE_MEGABYTE * 256)
+#define VALID_AVAIL_START_PFN_5 atop(ONE_MEGABYTE + 1)
+#define VALID_AVAIL_END_PFN_5 atop(ONE_MEGABYTE * 256)
+
+/*
+ * Total number of pages (of 4K size each) should be 256 for 1MB of memory.
+ */
+#define PAGE_COUNT_1M 256
+
+/*
+ * The number of Page Frames to allot per segment
+ */
+#define PF_STEP 8
+
+/*
+ * A debug fucntion to print the content of upm.
+ */
+ static inline void
+ uvm_physseg_dump_seg(uvm_physseg_t upm)
+ {
+#if defined(DEBUG)
+ printf("%s: seg->start == %ld\n", __func__,
+ uvm_physseg_get_start(upm));
+ printf("%s: seg->end == %ld\n", __func__,
+ uvm_physseg_get_end(upm));
+ printf("%s: seg->avail_start == %ld\n", __func__,
+ uvm_physseg_get_avail_start(upm));
+ printf("%s: seg->avail_end == %ld\n", __func__,
+ uvm_physseg_get_avail_end(upm));
+
+ printf("====\n\n");
+#else
+ return;
+#endif /* DEBUG */
+ }
+
+/*
+ * Private accessor that gets the value of vm_physmem.nentries
+ */
+static int
+uvm_physseg_get_entries(void)
+{
+#if defined(UVM_HOTPLUG)
+ return uvm_physseg_graph.nentries;
+#else
+ return vm_nphysmem;
+#endif /* UVM_HOTPLUG */
+}
+
+/*
+ * Note: This function replicates verbatim what happens in
+ * uvm_page.c:uvm_page_init().
+ *
+ * Please track any changes that happen there.
+ */
+static void
+uvm_page_init_fake(struct vm_page *pagearray, psize_t pagecount)
+{
+ uvm_physseg_t bank;
+ size_t n;
+
+ for (bank = uvm_physseg_get_first(),
+ uvm_physseg_seg_chomp_slab(bank, pagearray, pagecount);
+ uvm_physseg_valid_p(bank);
+ bank = uvm_physseg_get_next(bank)) {
+
+ n = uvm_physseg_get_end(bank) - uvm_physseg_get_start(bank);
+ uvm_physseg_seg_alloc_from_slab(bank, n);
+ uvm_physseg_init_seg(bank, pagearray);
+
+ /* set up page array pointers */
+ pagearray += n;
+ pagecount -= n;
+ }
+
+ uvm.page_init_done = true;
+}
+
+/*
+ * PHYS_TO_VM_PAGE: find vm_page for a PA. used by MI code to get vm_pages
+ * back from an I/O mapping (ugh!). used in some MD code as well.
+ */
+static struct vm_page *
+uvm_phys_to_vm_page(paddr_t pa)
+{
+ paddr_t pf = atop(pa);
+ paddr_t off;
+ uvm_physseg_t psi;
+
+ psi = uvm_physseg_find(pf, &off);
+ if (psi != UVM_PHYSSEG_TYPE_INVALID)
+ return uvm_physseg_get_pg(psi, off);
+ return(NULL);
+}
+
+//static paddr_t
+//uvm_vm_page_to_phys(const struct vm_page *pg)
+//{
+//
+// return pg->phys_addr;
+//}
+
+/*
+ * XXX: To do, write control test cases for uvm_vm_page_to_phys().
+ */
+
+/* #define VM_PAGE_TO_PHYS(entry) uvm_vm_page_to_phys(entry) */
+
+#define PHYS_TO_VM_PAGE(pa) uvm_phys_to_vm_page(pa)
+
+/*
+ * Test Fixture SetUp().
+ */
+static void
+setup(void)
+{
+ /* Prerequisites for running certain calls in uvm_physseg */
+ uvmexp.pagesize = PAGE_SIZE;
+ uvmexp.npages = 0;
+ uvm.page_init_done = false;
+ uvm_physseg_init();
+}
+
+ATF_TC(uvm_physseg_100);
+ATF_TC_HEAD(uvm_physseg_100, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 100 calls, VM_PHYSSEG_MAX is 32.");
+}
+ATF_TC_BODY(uvm_physseg_100, tc)
+{
+ paddr_t pa;
+
+ setup();
+
+ for(paddr_t i = VALID_START_PFN_1;
+ i < VALID_END_PFN_1; i += PF_STEP) {
+ uvm_page_physload(i, i + PF_STEP, i, i + PF_STEP,
+ VM_FREELIST_DEFAULT);
+ }
+
+ ATF_REQUIRE_EQ(VM_PHYSSEG_MAX, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(int i = 0; i < 100; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_1);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TC(uvm_physseg_1K);
+ATF_TC_HEAD(uvm_physseg_1K, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 1000 calls, VM_PHYSSEG_MAX is 32.");
+}
+ATF_TC_BODY(uvm_physseg_1K, tc)
+{
+ paddr_t pa;
+
+ setup();
+
+ for(paddr_t i = VALID_START_PFN_1;
+ i < VALID_END_PFN_1; i += PF_STEP) {
+ uvm_page_physload(i, i + PF_STEP, i, i + PF_STEP,
+ VM_FREELIST_DEFAULT);
+ }
+
+ ATF_REQUIRE_EQ(VM_PHYSSEG_MAX, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(int i = 0; i < 1000; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_1);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TC(uvm_physseg_10K);
+ATF_TC_HEAD(uvm_physseg_10K, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 10,000 calls, VM_PHYSSEG_MAX is 32.");
+}
+ATF_TC_BODY(uvm_physseg_10K, tc)
+{
+ paddr_t pa;
+
+ setup();
+
+ for(paddr_t i = VALID_START_PFN_1;
+ i < VALID_END_PFN_1; i += PF_STEP) {
+ uvm_page_physload(i, i + PF_STEP, i, i + PF_STEP,
+ VM_FREELIST_DEFAULT);
+ }
+
+ ATF_REQUIRE_EQ(VM_PHYSSEG_MAX, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(int i = 0; i < 10000; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_1);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TC(uvm_physseg_100K);
+ATF_TC_HEAD(uvm_physseg_100K, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 100,000 calls, VM_PHYSSEG_MAX is 32.");
+}
+ATF_TC_BODY(uvm_physseg_100K, tc)
+{
+ paddr_t pa;
+
+ setup();
+
+ for(paddr_t i = VALID_START_PFN_1;
+ i < VALID_END_PFN_1; i += PF_STEP) {
+ uvm_page_physload(i, i + PF_STEP, i, i + PF_STEP,
+ VM_FREELIST_DEFAULT);
+ }
+
+ ATF_REQUIRE_EQ(VM_PHYSSEG_MAX, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(int i = 0; i < 100000; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_1);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TC(uvm_physseg_1M);
+ATF_TC_HEAD(uvm_physseg_1M, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 1,000,000 calls, VM_PHYSSEG_MAX is 32.");
+}
+ATF_TC_BODY(uvm_physseg_1M, tc)
+{
+ paddr_t pa;
+
+ setup();
+
+ for(paddr_t i = VALID_START_PFN_1;
+ i < VALID_END_PFN_1; i += PF_STEP) {
+ uvm_page_physload(i, i + PF_STEP, i, i + PF_STEP,
+ VM_FREELIST_DEFAULT);
+ }
+
+ ATF_REQUIRE_EQ(VM_PHYSSEG_MAX, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(int i = 0; i < 1000000; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_1);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TC(uvm_physseg_10M);
+ATF_TC_HEAD(uvm_physseg_10M, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 10,000,000 calls, VM_PHYSSEG_MAX is 32.");
+}
+ATF_TC_BODY(uvm_physseg_10M, tc)
+{
+ paddr_t pa;
+
+ setup();
+
+ for(paddr_t i = VALID_START_PFN_1;
+ i < VALID_END_PFN_1; i += PF_STEP) {
+ uvm_page_physload(i, i + PF_STEP, i, i + PF_STEP,
+ VM_FREELIST_DEFAULT);
+ }
+
+ ATF_REQUIRE_EQ(VM_PHYSSEG_MAX, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(int i = 0; i < 10000000; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_1);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TC(uvm_physseg_100M);
+ATF_TC_HEAD(uvm_physseg_100M, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 100,000,000 calls, VM_PHYSSEG_MAX is 32.");
+}
+ATF_TC_BODY(uvm_physseg_100M, tc)
+{
+ paddr_t pa;
+
+ setup();
+
+ for(paddr_t i = VALID_START_PFN_1;
+ i < VALID_END_PFN_1; i += PF_STEP) {
+ uvm_page_physload(i, i + PF_STEP, i, i + PF_STEP,
+ VM_FREELIST_DEFAULT);
+ }
+
+ ATF_REQUIRE_EQ(VM_PHYSSEG_MAX, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(int i = 0; i < 100000000; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_1);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TC(uvm_physseg_1MB);
+ATF_TC_HEAD(uvm_physseg_1MB, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 10,000,000 calls, VM_PHYSSEG_MAX is 32 on 1 MB Segment.");
+}
+ATF_TC_BODY(uvm_physseg_1MB, t)
+{
+ paddr_t pa = 0;
+
+ paddr_t pf = 0;
+
+ psize_t pf_chunk_size = 0;
+
+ psize_t npages1 = (VALID_END_PFN_1 - VALID_START_PFN_1);
+
+ psize_t npages2 = (VALID_END_PFN_2 - VALID_START_PFN_2);
+
+ struct vm_page *slab = malloc(sizeof(struct vm_page) *
+ (npages1 + npages2));
+
+ setup();
+
+ /* We start with zero segments */
+ ATF_REQUIRE_EQ(true, uvm_physseg_plug(VALID_START_PFN_1, npages1, NULL));
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ /* Post boot: Fake all segments and pages accounted for. */
+ uvm_page_init_fake(slab, npages1 + npages2);
+
+ ATF_REQUIRE_EQ(true, uvm_physseg_plug(VALID_START_PFN_2, npages2, NULL));
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(pf = VALID_START_PFN_2; pf < VALID_END_PFN_2; pf += PF_STEP) {
+ pf_chunk_size = (psize_t) random() % (psize_t) (PF_STEP - 1) + 1;
+ uvm_physseg_unplug(pf, pf_chunk_size);
+ }
+
+ for(int i = 0; i < 10000000; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_2);
+ if(pa < ctob(VALID_START_PFN_2))
+ pa += ctob(VALID_START_PFN_2);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TC(uvm_physseg_64MB);
+ATF_TC_HEAD(uvm_physseg_64MB, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 10,000,000 calls, VM_PHYSSEG_MAX is 32 on 64 MB Segment.");
+}
+ATF_TC_BODY(uvm_physseg_64MB, t)
+{
+ paddr_t pa = 0;
+
+ paddr_t pf = 0;
+
+ psize_t pf_chunk_size = 0;
+
+ psize_t npages1 = (VALID_END_PFN_1 - VALID_START_PFN_1);
+
+ psize_t npages2 = (VALID_END_PFN_3 - VALID_START_PFN_3);
+
+ struct vm_page *slab = malloc(sizeof(struct vm_page) *
+ (npages1 + npages2));
+
+ setup();
+
+ /* We start with zero segments */
+ ATF_REQUIRE_EQ(true, uvm_physseg_plug(VALID_START_PFN_1, npages1, NULL));
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ /* Post boot: Fake all segments and pages accounted for. */
+ uvm_page_init_fake(slab, npages1 + npages2);
+
+ ATF_REQUIRE_EQ(true, uvm_physseg_plug(VALID_START_PFN_3, npages2, NULL));
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(pf = VALID_START_PFN_3; pf < VALID_END_PFN_3; pf += PF_STEP) {
+ pf_chunk_size = (psize_t) random() % (psize_t) (PF_STEP - 1) + 1;
+ uvm_physseg_unplug(pf, pf_chunk_size);
+ }
+
+ for(int i = 0; i < 10000000; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_3);
+ if(pa < ctob(VALID_START_PFN_3))
+ pa += ctob(VALID_START_PFN_3);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TC(uvm_physseg_128MB);
+ATF_TC_HEAD(uvm_physseg_128MB, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 10,000,000 calls, VM_PHYSSEG_MAX is 32 on 128 MB Segment.");
+}
+ATF_TC_BODY(uvm_physseg_128MB, t)
+{
+ paddr_t pa = 0;
+
+ paddr_t pf = 0;
+
+ psize_t pf_chunk_size = 0;
+
+ psize_t npages1 = (VALID_END_PFN_1 - VALID_START_PFN_1);
+
+ psize_t npages2 = (VALID_END_PFN_4 - VALID_START_PFN_4);
+
+ struct vm_page *slab = malloc(sizeof(struct vm_page)
+ * (npages1 + npages2));
+
+ setup();
+
+ /* We start with zero segments */
+ ATF_REQUIRE_EQ(true, uvm_physseg_plug(VALID_START_PFN_1, npages1, NULL));
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ /* Post boot: Fake all segments and pages accounted for. */
+ uvm_page_init_fake(slab, npages1 + npages2);
+
+ ATF_REQUIRE_EQ(true, uvm_physseg_plug(VALID_START_PFN_2, npages2, NULL));
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(pf = VALID_START_PFN_4; pf < VALID_END_PFN_4; pf += PF_STEP) {
+ pf_chunk_size = (psize_t) random() % (psize_t) (PF_STEP - 1) + 1;
+ uvm_physseg_unplug(pf, pf_chunk_size);
+ }
+
+ for(int i = 0; i < 10000000; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_4);
+ if(pa < ctob(VALID_START_PFN_4))
+ pa += ctob(VALID_START_PFN_4);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TC(uvm_physseg_256MB);
+ATF_TC_HEAD(uvm_physseg_256MB, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Load test uvm_phys_to_vm_page() with \
+ 10,000,000 calls, VM_PHYSSEG_MAX is 32 on 256 MB Segment.");
+}
+ATF_TC_BODY(uvm_physseg_256MB, t)
+{
+ paddr_t pa = 0;
+
+ paddr_t pf = 0;
+
+ psize_t pf_chunk_size = 0;
+
+ psize_t npages1 = (VALID_END_PFN_1 - VALID_START_PFN_1);
+
+ psize_t npages2 = (VALID_END_PFN_5 - VALID_START_PFN_5);
+
+ struct vm_page *slab = malloc(sizeof(struct vm_page) * (npages1 + npages2));
+
+ setup();
+
+ /* We start with zero segments */
+ ATF_REQUIRE_EQ(true, uvm_physseg_plug(VALID_START_PFN_1, npages1, NULL));
+ ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
+
+ /* Post boot: Fake all segments and pages accounted for. */
+ uvm_page_init_fake(slab, npages1 + npages2);
+
+ ATF_REQUIRE_EQ(true, uvm_physseg_plug(VALID_START_PFN_2, npages2, NULL));
+ ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
+
+ srandom((unsigned)time(NULL));
+ for(pf = VALID_START_PFN_5; pf < VALID_END_PFN_5; pf += PF_STEP) {
+ pf_chunk_size = (psize_t) random() % (psize_t) (PF_STEP - 1) + 1;
+ uvm_physseg_unplug(pf, pf_chunk_size);
+ }
+
+ for(int i = 0; i < 10000000; i++) {
+ pa = (paddr_t) random() % (paddr_t) ctob(VALID_END_PFN_5);
+ if(pa < ctob(VALID_END_PFN_5))
+ pa += ctob(VALID_START_PFN_5);
+ PHYS_TO_VM_PAGE(pa);
+ }
+
+ ATF_CHECK_EQ(true, true);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ /* Fixed memory size tests. */
+ ATF_TP_ADD_TC(tp, uvm_physseg_100);
+ ATF_TP_ADD_TC(tp, uvm_physseg_1K);
+ ATF_TP_ADD_TC(tp, uvm_physseg_10K);
+ ATF_TP_ADD_TC(tp, uvm_physseg_100K);
+ ATF_TP_ADD_TC(tp, uvm_physseg_1M);
+ ATF_TP_ADD_TC(tp, uvm_physseg_10M);
+ ATF_TP_ADD_TC(tp, uvm_physseg_100M);
+
+#if defined(UVM_HOTPLUG)
+ /* Variable memory size tests. */
+ ATF_TP_ADD_TC(tp, uvm_physseg_1MB);
+ ATF_TP_ADD_TC(tp, uvm_physseg_64MB);
+ ATF_TP_ADD_TC(tp, uvm_physseg_128MB);
+ ATF_TP_ADD_TC(tp, uvm_physseg_256MB);
+#endif /* UVM_HOTPLUG */
+
+ return atf_no_error();
+}
diff --git a/usr.bin/mixerctl/t_mixerctl.sh b/usr.bin/mixerctl/t_mixerctl.sh
new file mode 100755
index 000000000000..94c0bdf8cdf4
--- /dev/null
+++ b/usr.bin/mixerctl/t_mixerctl.sh
@@ -0,0 +1,51 @@
+# $NetBSD: t_mixerctl.sh,v 1.1 2017/01/02 15:40:09 christos Exp $
+
+atf_test_case noargs_usage
+noargs_usage_head() {
+ atf_set "descr" "Ensure mixerctl(1) with no args prints a usage message"
+}
+noargs_usage_body() {
+ atf_check -s exit:0 -o not-empty -e ignore \
+ mixerctl
+}
+
+atf_test_case showvalue
+showvalue_head() {
+ atf_set "descr" "Ensure mixerctl(1) can print the value for all variables"
+}
+showvalue_body() {
+ for var in $(mixerctl -a | awk -F= '{print $1}'); do
+ atf_check -s exit:0 -e ignore -o match:"^${var}=" \
+ mixerctl ${var}
+ done
+}
+
+atf_test_case nflag
+nflag_head() {
+ atf_set "descr" "Ensure 'mixerctl -n' actually suppresses some output"
+}
+nflag_body() {
+ varname="$(mixerctl -a | head -1 | awk -F= '{print $1}')"
+
+ atf_check -s exit:0 -o match:"${varname}" -e ignore \
+ mixerctl ${varname}
+
+ atf_check -s exit:0 -o not-match:"${varname}" -e ignore \
+ mixerctl -n ${varname}
+}
+
+atf_test_case nonexistant_device
+nonexistant_device_head() {
+ atf_set "descr" "Ensure mixerctl(1) complains if provided a nonexistant mixer device"
+}
+nonexistant_device_body() {
+ atf_check -s not-exit:0 -o ignore -e match:"No such file" \
+ mixerctl -d /a/b/c/d/e
+}
+
+atf_init_test_cases() {
+ atf_add_test_case noargs_usage
+ atf_add_test_case showvalue
+ atf_add_test_case nflag
+ atf_add_test_case nonexistant_device
+}
diff --git a/usr.bin/uniq/d_basic.in b/usr.bin/uniq/d_basic.in
new file mode 100644
index 000000000000..52a24bcfbb8c
--- /dev/null
+++ b/usr.bin/uniq/d_basic.in
@@ -0,0 +1,4 @@
+1
+12
+1
+1
diff --git a/usr.bin/uniq/d_basic.out b/usr.bin/uniq/d_basic.out
new file mode 100644
index 000000000000..d44fcba56f35
--- /dev/null
+++ b/usr.bin/uniq/d_basic.out
@@ -0,0 +1,3 @@
+1
+12
+1
diff --git a/usr.bin/uniq/d_counts.out b/usr.bin/uniq/d_counts.out
new file mode 100644
index 000000000000..bb1c86ba3d6d
--- /dev/null
+++ b/usr.bin/uniq/d_counts.out
@@ -0,0 +1,6 @@
+ 1 #01 foo0 bar0 foo1 bar1
+ 1 #02 bar0 foo1 bar1 foo1
+ 1 #03 foo0 bar0 foo1 bar1
+ 1 #04
+ 2 #05 foo0 bar0 foo1 bar1
+ 1 #07 bar0 foo1 bar1 foo0
diff --git a/usr.bin/uniq/d_input.in b/usr.bin/uniq/d_input.in
new file mode 100644
index 000000000000..c32c44d44c0a
--- /dev/null
+++ b/usr.bin/uniq/d_input.in
@@ -0,0 +1,7 @@
+#01 foo0 bar0 foo1 bar1
+#02 bar0 foo1 bar1 foo1
+#03 foo0 bar0 foo1 bar1
+#04
+#05 foo0 bar0 foo1 bar1
+#06 foo0 bar0 foo1 bar1
+#07 bar0 foo1 bar1 foo0
diff --git a/usr.bin/uniq/d_show_duplicates.out b/usr.bin/uniq/d_show_duplicates.out
new file mode 100644
index 000000000000..45f4be7029a1
--- /dev/null
+++ b/usr.bin/uniq/d_show_duplicates.out
@@ -0,0 +1 @@
+#05 foo0 bar0 foo1 bar1
diff --git a/usr.bin/uniq/d_show_uniques.out b/usr.bin/uniq/d_show_uniques.out
new file mode 100644
index 000000000000..1cc2ecbf3058
--- /dev/null
+++ b/usr.bin/uniq/d_show_uniques.out
@@ -0,0 +1,5 @@
+#01 foo0 bar0 foo1 bar1
+#02 bar0 foo1 bar1 foo1
+#03 foo0 bar0 foo1 bar1
+#04
+#07 bar0 foo1 bar1 foo0
diff --git a/usr.bin/uniq/t_uniq.sh b/usr.bin/uniq/t_uniq.sh
new file mode 100755
index 000000000000..d90a4d595a86
--- /dev/null
+++ b/usr.bin/uniq/t_uniq.sh
@@ -0,0 +1,97 @@
+# $NetBSD: t_uniq.sh,v 1.1 2016/10/22 14:13:39 abhinav Exp $
+#
+# Copyright (c) 2016 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Abhinav Upadhyay
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+atf_test_case basic
+basic_head()
+{
+ atf_set "descr" "Checks the basic functionality"
+}
+basic_body()
+{
+ atf_check -o file:$(atf_get_srcdir)/d_basic.out uniq \
+ $(atf_get_srcdir)/d_basic.in
+}
+
+atf_test_case test_counts
+test_counts_head()
+{
+ atf_set "descr" "Tests the -c option, comparing each line of the input" \
+ "file data starting from the second field"
+}
+test_counts_body()
+{
+ atf_check -o file:$(atf_get_srcdir)/d_counts.out uniq -c -f 1 \
+ $(atf_get_srcdir)/d_input.in
+}
+
+atf_test_case show_duplicates
+show_duplicates_head()
+{
+ atf_set "descr" "Checks the -d option, comparing each line of the input" \
+ "file data starting from the second field"
+}
+show_duplicates_body()
+{
+ atf_check -o file:$(atf_get_srcdir)/d_show_duplicates.out uniq -d -f 1 \
+ $(atf_get_srcdir)/d_input.in
+}
+
+atf_test_case show_uniques
+show_uniques_head()
+{
+ atf_set "descr" "Checks the -u option, comparing each line of the input" \
+ "file data starting from the second field"
+}
+show_uniques_body()
+{
+ atf_check -o file:$(atf_get_srcdir)/d_show_uniques.out uniq -u -f 1 \
+ $(atf_get_srcdir)/d_input.in
+}
+
+atf_test_case show_duplicates_from_third_character
+show_duplicates_from_third_character_head()
+{
+ atf_set "descr" "Checks the -d option, comparing each line of the input" \
+ "file data starting from the third character (-s option)"
+}
+show_duplicates_from_third_character_body()
+{
+ atf_check -o empty uniq -d -s 2 $(atf_get_srcdir)/d_input.in
+
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case basic
+ atf_add_test_case test_counts
+ atf_add_test_case show_duplicates
+ atf_add_test_case show_uniques
+ atf_add_test_case show_duplicates_from_third_character
+}