xref: /illumos-gate/usr/src/tools/cpcgen/cpcgen.c (revision 08f1bbed)
17e3dbbacSRobert Mustacchi /*
27e3dbbacSRobert Mustacchi  * This file and its contents are supplied under the terms of the
37e3dbbacSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
47e3dbbacSRobert Mustacchi  * You may only use this file in accordance with the terms of version
57e3dbbacSRobert Mustacchi  * 1.0 of the CDDL.
67e3dbbacSRobert Mustacchi  *
77e3dbbacSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
87e3dbbacSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
97e3dbbacSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
107e3dbbacSRobert Mustacchi  */
117e3dbbacSRobert Mustacchi 
127e3dbbacSRobert Mustacchi /*
13*08f1bbedSJohn Levon  * Copyright (c) 2019, Joyent, Inc.
147e3dbbacSRobert Mustacchi  */
157e3dbbacSRobert Mustacchi 
167e3dbbacSRobert Mustacchi /*
177e3dbbacSRobert Mustacchi  * This file transforms the perfmon data files into C files and manual pages.
187e3dbbacSRobert Mustacchi  */
197e3dbbacSRobert Mustacchi 
207e3dbbacSRobert Mustacchi #include <stdio.h>
217e3dbbacSRobert Mustacchi #include <stdarg.h>
227e3dbbacSRobert Mustacchi #include <unistd.h>
237e3dbbacSRobert Mustacchi #include <err.h>
247e3dbbacSRobert Mustacchi #include <libgen.h>
257e3dbbacSRobert Mustacchi #include <libnvpair.h>
267e3dbbacSRobert Mustacchi #include <strings.h>
277e3dbbacSRobert Mustacchi #include <errno.h>
287e3dbbacSRobert Mustacchi #include <limits.h>
297e3dbbacSRobert Mustacchi #include <sys/mman.h>
307e3dbbacSRobert Mustacchi #include <sys/param.h>
317e3dbbacSRobert Mustacchi #include <assert.h>
327e3dbbacSRobert Mustacchi #include <ctype.h>
337e3dbbacSRobert Mustacchi #include <sys/types.h>
347e3dbbacSRobert Mustacchi #include <sys/stat.h>
357e3dbbacSRobert Mustacchi #include <fcntl.h>
367e3dbbacSRobert Mustacchi 
377e3dbbacSRobert Mustacchi #include <json_nvlist.h>
387e3dbbacSRobert Mustacchi 
397e3dbbacSRobert Mustacchi #define	EXIT_USAGE	2
407e3dbbacSRobert Mustacchi 
417e3dbbacSRobert Mustacchi 
427e3dbbacSRobert Mustacchi typedef struct cpc_proc {
437e3dbbacSRobert Mustacchi 	struct cpc_proc *cproc_next;
447e3dbbacSRobert Mustacchi 	uint_t		cproc_family;
457e3dbbacSRobert Mustacchi 	uint_t		cproc_model;
467e3dbbacSRobert Mustacchi } cpc_proc_t;
477e3dbbacSRobert Mustacchi 
487e3dbbacSRobert Mustacchi typedef enum cpc_file_type {
497e3dbbacSRobert Mustacchi 	CPC_FILE_CORE		= 1 << 0,
507e3dbbacSRobert Mustacchi 	CPC_FILE_OFF_CORE	= 1 << 1,
517e3dbbacSRobert Mustacchi 	CPC_FILE_UNCORE		= 1 << 2,
527e3dbbacSRobert Mustacchi 	CPC_FILE_FP_MATH	= 1 << 3,
537e3dbbacSRobert Mustacchi 	CPC_FILE_UNCORE_EXP	= 1 << 4
547e3dbbacSRobert Mustacchi } cpc_type_t;
557e3dbbacSRobert Mustacchi 
567e3dbbacSRobert Mustacchi typedef struct cpc_map {
577e3dbbacSRobert Mustacchi 	struct cpc_map	*cmap_next;
587e3dbbacSRobert Mustacchi 	cpc_type_t	cmap_type;
597e3dbbacSRobert Mustacchi 	nvlist_t	*cmap_data;
607e3dbbacSRobert Mustacchi 	char		*cmap_path;
617e3dbbacSRobert Mustacchi 	const char	*cmap_name;
627e3dbbacSRobert Mustacchi 	cpc_proc_t	*cmap_procs;
637e3dbbacSRobert Mustacchi } cpc_map_t;
647e3dbbacSRobert Mustacchi 
657e3dbbacSRobert Mustacchi typedef struct cpc_whitelist {
667e3dbbacSRobert Mustacchi 	const char	*cwhite_short;
677e3dbbacSRobert Mustacchi 	const char	*cwhite_human;
687e3dbbacSRobert Mustacchi 	uint_t		cwhite_mask;
697e3dbbacSRobert Mustacchi } cpc_whitelist_t;
707e3dbbacSRobert Mustacchi 
717e3dbbacSRobert Mustacchi /*
727e3dbbacSRobert Mustacchi  * List of architectures that we support generating this data for. This is done
737e3dbbacSRobert Mustacchi  * so that processors that illumos doesn't support or run on aren't generated
747e3dbbacSRobert Mustacchi  * (generally the Xeon Phi).
757e3dbbacSRobert Mustacchi  */
767e3dbbacSRobert Mustacchi static cpc_whitelist_t cpcgen_whitelist[] = {
777e3dbbacSRobert Mustacchi 	/* Nehalem */
787e3dbbacSRobert Mustacchi 	{ "NHM-EP", "nhm_ep", CPC_FILE_CORE },
797e3dbbacSRobert Mustacchi 	{ "NHM-EX", "nhm_ex", CPC_FILE_CORE },
807e3dbbacSRobert Mustacchi 	/* Westmere */
817e3dbbacSRobert Mustacchi 	{ "WSM-EP-DP", "wsm_ep_dp", CPC_FILE_CORE },
827e3dbbacSRobert Mustacchi 	{ "WSM-EP-SP", "wsm_ep_sp", CPC_FILE_CORE },
837e3dbbacSRobert Mustacchi 	{ "WSM-EX", "wsm_ex", CPC_FILE_CORE },
847e3dbbacSRobert Mustacchi 	/* Sandy Bridge */
857e3dbbacSRobert Mustacchi 	{ "SNB", "snb", CPC_FILE_CORE },
867e3dbbacSRobert Mustacchi 	{ "JKT", "jkt", CPC_FILE_CORE },
877e3dbbacSRobert Mustacchi 	/* Ivy Bridge */
887e3dbbacSRobert Mustacchi 	{ "IVB", "ivb", CPC_FILE_CORE },
897e3dbbacSRobert Mustacchi 	{ "IVT", "ivt", CPC_FILE_CORE },
907e3dbbacSRobert Mustacchi 	/* Haswell */
917e3dbbacSRobert Mustacchi 	{ "HSW", "hsw", CPC_FILE_CORE },
927e3dbbacSRobert Mustacchi 	{ "HSX", "hsx", CPC_FILE_CORE },
937e3dbbacSRobert Mustacchi 	/* Broadwell */
947e3dbbacSRobert Mustacchi 	{ "BDW", "bdw", CPC_FILE_CORE },
957e3dbbacSRobert Mustacchi 	{ "BDW-DE", "bdw_de", CPC_FILE_CORE },
967e3dbbacSRobert Mustacchi 	{ "BDX", "bdx", CPC_FILE_CORE },
977e3dbbacSRobert Mustacchi 	/* Skylake */
987e3dbbacSRobert Mustacchi 	{ "SKL", "skl", CPC_FILE_CORE },
997e3dbbacSRobert Mustacchi 	{ "SKX", "skx", CPC_FILE_CORE },
1007e3dbbacSRobert Mustacchi 	/* Atom */
1017e3dbbacSRobert Mustacchi 	{ "BNL", "bnl", CPC_FILE_CORE },
1027e3dbbacSRobert Mustacchi 	{ "SLM", "slm", CPC_FILE_CORE },
1037e3dbbacSRobert Mustacchi 	{ "GLM", "glm", CPC_FILE_CORE },
1047e3dbbacSRobert Mustacchi 	{ "GLP", "glp", CPC_FILE_CORE },
1057e3dbbacSRobert Mustacchi 	{ NULL }
1067e3dbbacSRobert Mustacchi };
1077e3dbbacSRobert Mustacchi 
1087e3dbbacSRobert Mustacchi typedef struct cpc_papi {
1097e3dbbacSRobert Mustacchi 	const char	*cpapi_intc;
1107e3dbbacSRobert Mustacchi 	const char	*cpapi_papi;
1117e3dbbacSRobert Mustacchi } cpc_papi_t;
1127e3dbbacSRobert Mustacchi 
1137e3dbbacSRobert Mustacchi /*
1147e3dbbacSRobert Mustacchi  * This table maps events with an Intel specific name to the corresponding PAPI
1157e3dbbacSRobert Mustacchi  * name. There may be multiple INtel events which map to the same PAPI event.
1167e3dbbacSRobert Mustacchi  * This is usually because different processors have different names for an
1177e3dbbacSRobert Mustacchi  * event. We use the title as opposed to the event codes because those can
1187e3dbbacSRobert Mustacchi  * change somewhat arbitrarily between processor generations.
1197e3dbbacSRobert Mustacchi  */
1207e3dbbacSRobert Mustacchi static cpc_papi_t cpcgen_papi_map[] = {
1217e3dbbacSRobert Mustacchi 	{ "CPU_CLK_UNHALTED.THREAD_P", "PAPI_tot_cyc" },
1227e3dbbacSRobert Mustacchi 	{ "INST_RETIRED.ANY_P", "PAPI_tot_ins" },
1237e3dbbacSRobert Mustacchi 	{ "BR_INST_RETIRED.ALL_BRANCHES", "PAPI_br_ins" },
1247e3dbbacSRobert Mustacchi 	{ "BR_MISP_RETIRED.ALL_BRANCHES", "PAPI_br_msp" },
1257e3dbbacSRobert Mustacchi 	{ "BR_INST_RETIRED.CONDITIONAL", "PAPI_br_cn" },
1267e3dbbacSRobert Mustacchi 	{ "CYCLE_ACTIVITY.CYCLES_L1D_MISS", "PAPI_l1_dcm" },
1277e3dbbacSRobert Mustacchi 	{ "L1I.HITS", "PAPI_l1_ich" },
1287e3dbbacSRobert Mustacchi 	{ "ICACHE.HIT", "PAPI_l1_ich" },
1297e3dbbacSRobert Mustacchi 	{ "L1I.MISS", "PAPI_L1_icm" },
1307e3dbbacSRobert Mustacchi 	{ "ICACHE.MISSES", "PAPI_l1_icm" },
1317e3dbbacSRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_ica" },
1327e3dbbacSRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_ica" },
1337e3dbbacSRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_icr" },
1347e3dbbacSRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_icr" },
1357e3dbbacSRobert Mustacchi 	{ "L2_RQSTS.CODE_RD_MISS", "PAPI_l2_icm" },
1367e3dbbacSRobert Mustacchi 	{ "L2_RQSTS.MISS", "PAPI_l2_tcm" },
1377e3dbbacSRobert Mustacchi 	{ "ITLB_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_im" },
1387e3dbbacSRobert Mustacchi 	{ "DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_dm" },
1397e3dbbacSRobert Mustacchi 	{ "PAGE_WALKS.D_SIDE_WALKS", "PAPI_tlb_dm" },
1407e3dbbacSRobert Mustacchi 	{ "PAGE_WALKS.I_SIDE_WALKS", "PAPI_tlb_im" },
1417e3dbbacSRobert Mustacchi 	{ "PAGE_WALKS.WALKS", "PAPI_tlb_tl" },
1427e3dbbacSRobert Mustacchi 	{ "INST_QUEUE_WRITES", "PAPI_tot_iis" },
1437e3dbbacSRobert Mustacchi 	{ "MEM_INST_RETIRED.STORES" "PAPI_sr_ins" },
1447e3dbbacSRobert Mustacchi 	{ "MEM_INST_RETIRED.LOADS" "PAPI_ld_ins" },
1457e3dbbacSRobert Mustacchi 	{ NULL, NULL }
1467e3dbbacSRobert Mustacchi };
1477e3dbbacSRobert Mustacchi 
1487e3dbbacSRobert Mustacchi typedef struct cpcgen_ops {
1497e3dbbacSRobert Mustacchi 	char *(*cgen_op_name)(cpc_map_t *);
1507e3dbbacSRobert Mustacchi 	boolean_t (*cgen_op_file_before)(FILE *, cpc_map_t *);
1517e3dbbacSRobert Mustacchi 	boolean_t (*cgen_op_file_after)(FILE *, cpc_map_t *);
1527e3dbbacSRobert Mustacchi 	boolean_t (*cgen_op_event)(FILE *, nvlist_t *, const char *, uint32_t);
1537e3dbbacSRobert Mustacchi } cpcgen_ops_t;
1547e3dbbacSRobert Mustacchi 
1557e3dbbacSRobert Mustacchi static cpcgen_ops_t cpcgen_ops;
1567e3dbbacSRobert Mustacchi static const char *cpcgen_mapfile = "/mapfile.csv";
1577e3dbbacSRobert Mustacchi static const char *cpcgen_progname;
1587e3dbbacSRobert Mustacchi static cpc_map_t *cpcgen_maps;
1597e3dbbacSRobert Mustacchi 
1607e3dbbacSRobert Mustacchi /*
1617e3dbbacSRobert Mustacchi  * Constants used for generating data.
1627e3dbbacSRobert Mustacchi  */
1637e3dbbacSRobert Mustacchi /* BEGIN CSTYLED */
1647e3dbbacSRobert Mustacchi static const char *cpcgen_cfile_header = ""
1657e3dbbacSRobert Mustacchi "/*\n"
1667e3dbbacSRobert Mustacchi " *  Copyright (c) 2018, Intel Corporation\n"
1677e3dbbacSRobert Mustacchi " *  Copyright (c) 2018, Joyent, Inc\n"
1687e3dbbacSRobert Mustacchi " *  All rights reserved.\n"
1697e3dbbacSRobert Mustacchi " *\n"
1707e3dbbacSRobert Mustacchi " *  Redistribution and use in source and binary forms, with or without\n"
1717e3dbbacSRobert Mustacchi " *  modification, are permitted provided that the following conditions are met:\n"
1727e3dbbacSRobert Mustacchi " * \n"
1737e3dbbacSRobert Mustacchi " *   1. Redistributions of source code must retain the above copyright notice,\n"
1747e3dbbacSRobert Mustacchi " *      this list of conditions and the following disclaimer.\n"
1757e3dbbacSRobert Mustacchi " * \n"
1767e3dbbacSRobert Mustacchi " *   2. Redistributions in binary form must reproduce the above copyright \n"
1777e3dbbacSRobert Mustacchi " *      notice, this list of conditions and the following disclaimer in the\n"
1787e3dbbacSRobert Mustacchi " *      documentation and/or other materials provided with the distribution.\n"
1797e3dbbacSRobert Mustacchi " * \n"
1807e3dbbacSRobert Mustacchi " *   3. Neither the name of the Intel Corporation nor the names of its \n"
1817e3dbbacSRobert Mustacchi " *      contributors may be used to endorse or promote products derived from\n"
1827e3dbbacSRobert Mustacchi " *      this software without specific prior written permission.\n"
1837e3dbbacSRobert Mustacchi " *\n"
1847e3dbbacSRobert Mustacchi " *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
1857e3dbbacSRobert Mustacchi " *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
1867e3dbbacSRobert Mustacchi " *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
1877e3dbbacSRobert Mustacchi " *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
1887e3dbbacSRobert Mustacchi " *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
1897e3dbbacSRobert Mustacchi " *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
1907e3dbbacSRobert Mustacchi " *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
1917e3dbbacSRobert Mustacchi " *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
1927e3dbbacSRobert Mustacchi " *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
1937e3dbbacSRobert Mustacchi " *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
1947e3dbbacSRobert Mustacchi " *  POSSIBILITY OF SUCH DAMAGE.\n"
1957e3dbbacSRobert Mustacchi " *\n"
1967e3dbbacSRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n"
1977e3dbbacSRobert Mustacchi " * data/perfmon%s\n"
1987e3dbbacSRobert Mustacchi " *\n"
1997e3dbbacSRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
2007e3dbbacSRobert Mustacchi " */\n"
2017e3dbbacSRobert Mustacchi "\n";
2027e3dbbacSRobert Mustacchi /* END CSTYLED */
2037e3dbbacSRobert Mustacchi 
2047e3dbbacSRobert Mustacchi static const char *cpcgen_cfile_table_start = ""
2057e3dbbacSRobert Mustacchi "#include <core_pcbe_table.h>\n"
2067e3dbbacSRobert Mustacchi "\n"
2077e3dbbacSRobert Mustacchi "const struct events_table_t pcbe_core_events_%s[] = {\n";
2087e3dbbacSRobert Mustacchi 
2097e3dbbacSRobert Mustacchi static const char *cpcgen_cfile_table_end = ""
2107e3dbbacSRobert Mustacchi "\t{ NT_END, 0, 0, \"\" }\n"
2117e3dbbacSRobert Mustacchi "};\n";
2127e3dbbacSRobert Mustacchi 
2137e3dbbacSRobert Mustacchi /* BEGIN CSTYLED */
2147e3dbbacSRobert Mustacchi static const char *cpcgen_manual_header = ""
2157e3dbbacSRobert Mustacchi ".\\\" Copyright (c) 2018, Intel Corporation \n"
2167e3dbbacSRobert Mustacchi ".\\\" Copyright (c) 2018, Joyent, Inc.\n"
2177e3dbbacSRobert Mustacchi ".\\\" All rights reserved.\n"
2187e3dbbacSRobert Mustacchi ".\\\"\n"
2197e3dbbacSRobert Mustacchi ".\\\" Redistribution and use in source and binary forms, with or without \n"
2207e3dbbacSRobert Mustacchi ".\\\" modification, are permitted provided that the following conditions are met:\n"
2217e3dbbacSRobert Mustacchi ".\\\"\n"
2227e3dbbacSRobert Mustacchi ".\\\"  1. Redistributions of source code must retain the above copyright notice,\n"
2237e3dbbacSRobert Mustacchi ".\\\"     this list of conditions and the following disclaimer.\n"
2247e3dbbacSRobert Mustacchi ".\\\"\n"
2257e3dbbacSRobert Mustacchi ".\\\"  2. Redistributions in binary form must reproduce the above copyright\n"
2267e3dbbacSRobert Mustacchi ".\\\"     notice, this list of conditions and the following disclaimer in the\n"
2277e3dbbacSRobert Mustacchi ".\\\"     documentation and/or other materials provided with the distribution.\n"
2287e3dbbacSRobert Mustacchi ".\\\"\n"
2297e3dbbacSRobert Mustacchi ".\\\"  3. Neither the name of the Intel Corporation nor the names of its\n"
2307e3dbbacSRobert Mustacchi ".\\\"     contributors may be used to endorse or promote products derived from\n"
2317e3dbbacSRobert Mustacchi ".\\\"     this software without specific prior written permission.\n"
2327e3dbbacSRobert Mustacchi ".\\\"\n"
2337e3dbbacSRobert Mustacchi ".\\\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
2347e3dbbacSRobert Mustacchi ".\\\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
2357e3dbbacSRobert Mustacchi ".\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
2367e3dbbacSRobert Mustacchi ".\\\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
2377e3dbbacSRobert Mustacchi ".\\\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
2387e3dbbacSRobert Mustacchi ".\\\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
2397e3dbbacSRobert Mustacchi ".\\\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
2407e3dbbacSRobert Mustacchi ".\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
2417e3dbbacSRobert Mustacchi ".\\\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
2427e3dbbacSRobert Mustacchi ".\\\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
2437e3dbbacSRobert Mustacchi ".\\\" POSSIBILITY OF SUCH DAMAGE.\n"
2447e3dbbacSRobert Mustacchi ".\\\"\n"
2457e3dbbacSRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n"
2467e3dbbacSRobert Mustacchi ".\\\" data/perfmon%s\n"
2477e3dbbacSRobert Mustacchi ".\\\"\n"
2487e3dbbacSRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n"
2497e3dbbacSRobert Mustacchi ".\\\"\n"
2507e3dbbacSRobert Mustacchi ".\\\" We would like to thank Intel for providing the perfmon data for use in\n"
2517e3dbbacSRobert Mustacchi ".\\\" our manual pages.\n"
2527e3dbbacSRobert Mustacchi ".Dd June 18, 2018\n"
2537e3dbbacSRobert Mustacchi ".Dt %s_EVENTS 3CPC\n"
2547e3dbbacSRobert Mustacchi ".Os\n"
2557e3dbbacSRobert Mustacchi ".Sh NAME\n"
2567e3dbbacSRobert Mustacchi ".Nm %s_events\n"
2577e3dbbacSRobert Mustacchi ".Nd processor model specific performance counter events\n"
2587e3dbbacSRobert Mustacchi ".Sh DESCRIPTION\n"
2597e3dbbacSRobert Mustacchi "This manual page describes events specific to the following Intel CPU\n"
2607e3dbbacSRobert Mustacchi "models and is derived from Intel's perfmon data.\n"
2617e3dbbacSRobert Mustacchi "For more information, please consult the Intel Software Developer's Manual "
2627e3dbbacSRobert Mustacchi "or Intel's perfmon website.\n"
2637e3dbbacSRobert Mustacchi ".Pp\n"
2647e3dbbacSRobert Mustacchi "CPU models described by this document:\n"
2657e3dbbacSRobert Mustacchi ".Bl -bullet\n";
2667e3dbbacSRobert Mustacchi /* END CSTYLED */
2677e3dbbacSRobert Mustacchi 
2687e3dbbacSRobert Mustacchi static const char *cpcgen_manual_data = ""
2697e3dbbacSRobert Mustacchi ".El\n"
2707e3dbbacSRobert Mustacchi ".Pp\n"
2717e3dbbacSRobert Mustacchi "The following events are supported:\n"
2727e3dbbacSRobert Mustacchi ".Bl -tag -width Sy\n";
2737e3dbbacSRobert Mustacchi 
2747e3dbbacSRobert Mustacchi static const char *cpcgen_manual_trailer = ""
2757e3dbbacSRobert Mustacchi ".El\n"
2767e3dbbacSRobert Mustacchi ".Sh SEE ALSO\n"
2777e3dbbacSRobert Mustacchi ".Xr cpc 3CPC\n"
2787e3dbbacSRobert Mustacchi ".Pp\n"
2797e3dbbacSRobert Mustacchi ".Lk https://download.01.org/perfmon/index/";
2807e3dbbacSRobert Mustacchi 
2817e3dbbacSRobert Mustacchi static cpc_map_t *
2827e3dbbacSRobert Mustacchi cpcgen_map_lookup(const char *path)
2837e3dbbacSRobert Mustacchi {
2847e3dbbacSRobert Mustacchi 	cpc_map_t *m;
2857e3dbbacSRobert Mustacchi 
2867e3dbbacSRobert Mustacchi 	for (m = cpcgen_maps; m != NULL; m = m->cmap_next) {
2877e3dbbacSRobert Mustacchi 		if (strcmp(path, m->cmap_path) == 0) {
2887e3dbbacSRobert Mustacchi 			return (m);
2897e3dbbacSRobert Mustacchi 		}
2907e3dbbacSRobert Mustacchi 	}
2917e3dbbacSRobert Mustacchi 
2927e3dbbacSRobert Mustacchi 	return (NULL);
2937e3dbbacSRobert Mustacchi }
2947e3dbbacSRobert Mustacchi 
2957e3dbbacSRobert Mustacchi /*
2967e3dbbacSRobert Mustacchi  * Parse a string of the form 'GenuineIntel-6-2E' and get out the family and
2977e3dbbacSRobert Mustacchi  * model.
2987e3dbbacSRobert Mustacchi  */
2997e3dbbacSRobert Mustacchi static void
3007e3dbbacSRobert Mustacchi cpcgen_parse_model(char *fsr, uint_t *family, uint_t *model)
3017e3dbbacSRobert Mustacchi {
3027e3dbbacSRobert Mustacchi 	const char *bstr = "GenuineIntel";
3037e3dbbacSRobert Mustacchi 	const char *brand, *fam, *mod;
3047e3dbbacSRobert Mustacchi 	char *last;
3057e3dbbacSRobert Mustacchi 	long l;
3067e3dbbacSRobert Mustacchi 
3077e3dbbacSRobert Mustacchi 	if ((brand = strtok_r(fsr, "-", &last)) == NULL ||
3087e3dbbacSRobert Mustacchi 	    (fam = strtok_r(NULL, "-", &last)) == NULL ||
3097e3dbbacSRobert Mustacchi 	    (mod = strtok_r(NULL, "-", &last)) == NULL) {
3107e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse processor id \"%s\"", fsr);
3117e3dbbacSRobert Mustacchi 	}
3127e3dbbacSRobert Mustacchi 
3137e3dbbacSRobert Mustacchi 	if (strcmp(bstr, brand) != 0) {
3147e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "brand string \"%s\" did not match \"%s\"",
3157e3dbbacSRobert Mustacchi 		    brand, bstr);
3167e3dbbacSRobert Mustacchi 	}
3177e3dbbacSRobert Mustacchi 
3187e3dbbacSRobert Mustacchi 	errno = 0;
3197e3dbbacSRobert Mustacchi 	l = strtol(fam, &last, 16);
320*08f1bbedSJohn Levon 	if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') {
3217e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse family \"%s\"", fam);
3227e3dbbacSRobert Mustacchi 	}
3237e3dbbacSRobert Mustacchi 	*family = (uint_t)l;
3247e3dbbacSRobert Mustacchi 
3257e3dbbacSRobert Mustacchi 	l = strtol(mod, &last, 16);
326*08f1bbedSJohn Levon 	if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') {
3277e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse model \"%s\"", mod);
3287e3dbbacSRobert Mustacchi 	}
3297e3dbbacSRobert Mustacchi 	*model = (uint_t)l;
3307e3dbbacSRobert Mustacchi }
3317e3dbbacSRobert Mustacchi 
3327e3dbbacSRobert Mustacchi static nvlist_t *
3337e3dbbacSRobert Mustacchi cpcgen_read_datafile(const char *datadir, const char *file)
3347e3dbbacSRobert Mustacchi {
3357e3dbbacSRobert Mustacchi 	int fd;
3367e3dbbacSRobert Mustacchi 	char *path;
3377e3dbbacSRobert Mustacchi 	struct stat st;
3387e3dbbacSRobert Mustacchi 	void *map;
3397e3dbbacSRobert Mustacchi 	nvlist_t *nvl;
3407e3dbbacSRobert Mustacchi 	nvlist_parse_json_error_t jerr;
3417e3dbbacSRobert Mustacchi 
3427e3dbbacSRobert Mustacchi 	if (asprintf(&path, "%s/%s", datadir, file) == -1) {
3437e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to data file %s",
3447e3dbbacSRobert Mustacchi 		    file);
3457e3dbbacSRobert Mustacchi 	}
3467e3dbbacSRobert Mustacchi 
3477e3dbbacSRobert Mustacchi 	if ((fd = open(path, O_RDONLY)) < 0) {
3487e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data file %s", path);
3497e3dbbacSRobert Mustacchi 	}
3507e3dbbacSRobert Mustacchi 
3517e3dbbacSRobert Mustacchi 	if (fstat(fd, &st) != 0) {
3527e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to stat %s", path);
3537e3dbbacSRobert Mustacchi 	}
3547e3dbbacSRobert Mustacchi 
3557e3dbbacSRobert Mustacchi 	if ((map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
3567e3dbbacSRobert Mustacchi 	    fd, 0)) == MAP_FAILED) {
3577e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to mmap %s", path);
3587e3dbbacSRobert Mustacchi 	}
3597e3dbbacSRobert Mustacchi 
3607e3dbbacSRobert Mustacchi 	if (nvlist_parse_json(map, st.st_size, &nvl, NVJSON_FORCE_INTEGER,
3617e3dbbacSRobert Mustacchi 	    &jerr) != 0) {
3627e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse file %s at pos %ld: %s",
3637e3dbbacSRobert Mustacchi 		    path, jerr.nje_pos, jerr.nje_message);
3647e3dbbacSRobert Mustacchi 	}
3657e3dbbacSRobert Mustacchi 
3667e3dbbacSRobert Mustacchi 	if (munmap(map, st.st_size) != 0) {
3677e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to munmap %s", path);
3687e3dbbacSRobert Mustacchi 	}
3697e3dbbacSRobert Mustacchi 
3707e3dbbacSRobert Mustacchi 	if (close(fd) != 0) {
3717e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to close data file %s", path);
3727e3dbbacSRobert Mustacchi 	}
3737e3dbbacSRobert Mustacchi 	free(path);
3747e3dbbacSRobert Mustacchi 
3757e3dbbacSRobert Mustacchi 	return (nvl);
3767e3dbbacSRobert Mustacchi }
3777e3dbbacSRobert Mustacchi 
3787e3dbbacSRobert Mustacchi /*
3797e3dbbacSRobert Mustacchi  * Check the whitelist to see if we should use this model.
3807e3dbbacSRobert Mustacchi  */
3817e3dbbacSRobert Mustacchi static const char *
3827e3dbbacSRobert Mustacchi cpcgen_use_arch(const char *path, cpc_type_t type, const char *platform)
3837e3dbbacSRobert Mustacchi {
3847e3dbbacSRobert Mustacchi 	const char *slash;
3857e3dbbacSRobert Mustacchi 	size_t len;
3867e3dbbacSRobert Mustacchi 	uint_t i;
3877e3dbbacSRobert Mustacchi 
3887e3dbbacSRobert Mustacchi 	if (*path != '/') {
3897e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
3907e3dbbacSRobert Mustacchi 		    "leading '/'", path);
3917e3dbbacSRobert Mustacchi 	}
3927e3dbbacSRobert Mustacchi 	if ((slash = strchr(path + 1, '/')) == NULL) {
3937e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
3947e3dbbacSRobert Mustacchi 		    "second '/'", path);
3957e3dbbacSRobert Mustacchi 	}
3967e3dbbacSRobert Mustacchi 	/* Account for the last '/' character. */
3977e3dbbacSRobert Mustacchi 	len = slash - path - 1;
3987e3dbbacSRobert Mustacchi 	assert(len > 0);
3997e3dbbacSRobert Mustacchi 
4007e3dbbacSRobert Mustacchi 	for (i = 0; cpcgen_whitelist[i].cwhite_short != NULL; i++) {
4017e3dbbacSRobert Mustacchi 		if (platform != NULL && strcasecmp(platform,
4027e3dbbacSRobert Mustacchi 		    cpcgen_whitelist[i].cwhite_short) != 0)
4037e3dbbacSRobert Mustacchi 			continue;
4047e3dbbacSRobert Mustacchi 		if (strncmp(path + 1, cpcgen_whitelist[i].cwhite_short,
4057e3dbbacSRobert Mustacchi 		    len) == 0 &&
4067e3dbbacSRobert Mustacchi 		    (cpcgen_whitelist[i].cwhite_mask & type) == type) {
4077e3dbbacSRobert Mustacchi 			return (cpcgen_whitelist[i].cwhite_human);
4087e3dbbacSRobert Mustacchi 		}
4097e3dbbacSRobert Mustacchi 	}
4107e3dbbacSRobert Mustacchi 
4117e3dbbacSRobert Mustacchi 	return (NULL);
4127e3dbbacSRobert Mustacchi }
4137e3dbbacSRobert Mustacchi 
4147e3dbbacSRobert Mustacchi /*
4157e3dbbacSRobert Mustacchi  * Read in the mapfile.csv that is used to map between processor families and
4167e3dbbacSRobert Mustacchi  * parse this. Each line has a comma separated value.
4177e3dbbacSRobert Mustacchi  */
4187e3dbbacSRobert Mustacchi static void
4197e3dbbacSRobert Mustacchi cpcgen_read_mapfile(const char *datadir, const char *platform)
4207e3dbbacSRobert Mustacchi {
4217e3dbbacSRobert Mustacchi 	FILE *map;
4227e3dbbacSRobert Mustacchi 	char *mappath, *last;
4237e3dbbacSRobert Mustacchi 	char *data = NULL;
4247e3dbbacSRobert Mustacchi 	size_t datalen = 0;
4257e3dbbacSRobert Mustacchi 	uint_t lineno;
4267e3dbbacSRobert Mustacchi 
4277e3dbbacSRobert Mustacchi 	if (asprintf(&mappath, "%s/%s", datadir, cpcgen_mapfile) == -1) {
4287e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to mapfile");
4297e3dbbacSRobert Mustacchi 	}
4307e3dbbacSRobert Mustacchi 
4317e3dbbacSRobert Mustacchi 	if ((map = fopen(mappath, "r")) == NULL) {
4327e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data mapfile %s", mappath);
4337e3dbbacSRobert Mustacchi 	}
4347e3dbbacSRobert Mustacchi 
4357e3dbbacSRobert Mustacchi 	lineno = 0;
4367e3dbbacSRobert Mustacchi 	while (getline(&data, &datalen, map) != -1) {
4377e3dbbacSRobert Mustacchi 		char *fstr, *path, *tstr;
4387e3dbbacSRobert Mustacchi 		const char *name;
4397e3dbbacSRobert Mustacchi 		uint_t family, model;
4407e3dbbacSRobert Mustacchi 		cpc_type_t type;
4417e3dbbacSRobert Mustacchi 		cpc_map_t *map;
4427e3dbbacSRobert Mustacchi 		cpc_proc_t *proc;
4437e3dbbacSRobert Mustacchi 
4447e3dbbacSRobert Mustacchi 		/*
4457e3dbbacSRobert Mustacchi 		 * The first line contains the header:
4467e3dbbacSRobert Mustacchi 		 * Family-model,Version,Filename,EventType
4477e3dbbacSRobert Mustacchi 		 */
4487e3dbbacSRobert Mustacchi 		lineno++;
4497e3dbbacSRobert Mustacchi 		if (lineno == 1) {
4507e3dbbacSRobert Mustacchi 			continue;
4517e3dbbacSRobert Mustacchi 		}
4527e3dbbacSRobert Mustacchi 
4537e3dbbacSRobert Mustacchi 		if ((fstr = strtok_r(data, ",", &last)) == NULL ||
4547e3dbbacSRobert Mustacchi 		    strtok_r(NULL, ",", &last) == NULL ||
4557e3dbbacSRobert Mustacchi 		    (path = strtok_r(NULL, ",", &last)) == NULL ||
4567e3dbbacSRobert Mustacchi 		    (tstr = strtok_r(NULL, "\n", &last)) == NULL) {
4577e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse mapfile line "
4587e3dbbacSRobert Mustacchi 			    "%u in %s", lineno, mappath);
4597e3dbbacSRobert Mustacchi 		}
4607e3dbbacSRobert Mustacchi 
4617e3dbbacSRobert Mustacchi 		cpcgen_parse_model(fstr, &family, &model);
4627e3dbbacSRobert Mustacchi 
4637e3dbbacSRobert Mustacchi 		if (strcmp(tstr, "core") == 0) {
4647e3dbbacSRobert Mustacchi 			type = CPC_FILE_CORE;
4657e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "offcore") == 0) {
4667e3dbbacSRobert Mustacchi 			type = CPC_FILE_OFF_CORE;
4677e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "uncore") == 0) {
4687e3dbbacSRobert Mustacchi 			type = CPC_FILE_UNCORE;
4697e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "fp_arith_inst") == 0) {
4707e3dbbacSRobert Mustacchi 			type = CPC_FILE_FP_MATH;
4717e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "uncore experimental") == 0) {
4727e3dbbacSRobert Mustacchi 			type = CPC_FILE_UNCORE_EXP;
4737e3dbbacSRobert Mustacchi 		} else {
4747e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "unknown file type \"%s\" on line "
4757e3dbbacSRobert Mustacchi 			    "%u", tstr, lineno);
4767e3dbbacSRobert Mustacchi 		}
4777e3dbbacSRobert Mustacchi 
4787e3dbbacSRobert Mustacchi 		if ((name = cpcgen_use_arch(path, type, platform)) == NULL)
4797e3dbbacSRobert Mustacchi 			continue;
4807e3dbbacSRobert Mustacchi 
4817e3dbbacSRobert Mustacchi 		if ((map = cpcgen_map_lookup(path)) == NULL) {
4827e3dbbacSRobert Mustacchi 			nvlist_t *parsed;
4837e3dbbacSRobert Mustacchi 
4847e3dbbacSRobert Mustacchi 			parsed = cpcgen_read_datafile(datadir, path);
4857e3dbbacSRobert Mustacchi 
4867e3dbbacSRobert Mustacchi 			if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) {
4877e3dbbacSRobert Mustacchi 				err(EXIT_FAILURE, "failed to allocate space "
4887e3dbbacSRobert Mustacchi 				    "for cpc file");
4897e3dbbacSRobert Mustacchi 			}
4907e3dbbacSRobert Mustacchi 
4917e3dbbacSRobert Mustacchi 			if ((map->cmap_path = strdup(path)) == NULL) {
4927e3dbbacSRobert Mustacchi 				err(EXIT_FAILURE, "failed to duplicate path "
4937e3dbbacSRobert Mustacchi 				    "string");
4947e3dbbacSRobert Mustacchi 			}
4957e3dbbacSRobert Mustacchi 
4967e3dbbacSRobert Mustacchi 			map->cmap_type = type;
4977e3dbbacSRobert Mustacchi 			map->cmap_data = parsed;
4987e3dbbacSRobert Mustacchi 			map->cmap_next = cpcgen_maps;
4997e3dbbacSRobert Mustacchi 			map->cmap_name = name;
5007e3dbbacSRobert Mustacchi 			cpcgen_maps = map;
5017e3dbbacSRobert Mustacchi 		}
5027e3dbbacSRobert Mustacchi 
5037e3dbbacSRobert Mustacchi 		if ((proc = malloc(sizeof (cpc_proc_t))) == NULL) {
5047e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
5057e3dbbacSRobert Mustacchi 			    "family and model tracking");
5067e3dbbacSRobert Mustacchi 		}
5077e3dbbacSRobert Mustacchi 
5087e3dbbacSRobert Mustacchi 		proc->cproc_family = family;
5097e3dbbacSRobert Mustacchi 		proc->cproc_model = model;
5107e3dbbacSRobert Mustacchi 		proc->cproc_next = map->cmap_procs;
5117e3dbbacSRobert Mustacchi 		map->cmap_procs = proc;
5127e3dbbacSRobert Mustacchi 	}
5137e3dbbacSRobert Mustacchi 
5147e3dbbacSRobert Mustacchi 	if (errno != 0 || ferror(map)) {
5157e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to read %s", mappath);
5167e3dbbacSRobert Mustacchi 	}
5177e3dbbacSRobert Mustacchi 
5187e3dbbacSRobert Mustacchi 	if (fclose(map) == EOF) {
5197e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to close %s", mappath);
5207e3dbbacSRobert Mustacchi 	}
5217e3dbbacSRobert Mustacchi 	free(data);
5227e3dbbacSRobert Mustacchi 	free(mappath);
5237e3dbbacSRobert Mustacchi }
5247e3dbbacSRobert Mustacchi 
5257e3dbbacSRobert Mustacchi static char *
5267e3dbbacSRobert Mustacchi cpcgen_manual_name(cpc_map_t *map)
5277e3dbbacSRobert Mustacchi {
5287e3dbbacSRobert Mustacchi 	char *name;
5297e3dbbacSRobert Mustacchi 
5307e3dbbacSRobert Mustacchi 	if (asprintf(&name, "%s_events.3cpc", map->cmap_name) == -1) {
5317e3dbbacSRobert Mustacchi 		warn("failed to assemble manual page name for %s",
5327e3dbbacSRobert Mustacchi 		    map->cmap_path);
5337e3dbbacSRobert Mustacchi 		return (NULL);
5347e3dbbacSRobert Mustacchi 	}
5357e3dbbacSRobert Mustacchi 
5367e3dbbacSRobert Mustacchi 	return (name);
5377e3dbbacSRobert Mustacchi }
5387e3dbbacSRobert Mustacchi 
5397e3dbbacSRobert Mustacchi static boolean_t
5407e3dbbacSRobert Mustacchi cpcgen_manual_file_before(FILE *f, cpc_map_t *map)
5417e3dbbacSRobert Mustacchi {
5427e3dbbacSRobert Mustacchi 	size_t i;
5437e3dbbacSRobert Mustacchi 	char *upper;
5447e3dbbacSRobert Mustacchi 	cpc_proc_t *proc;
5457e3dbbacSRobert Mustacchi 
5467e3dbbacSRobert Mustacchi 	if ((upper = strdup(map->cmap_name)) == NULL) {
5477e3dbbacSRobert Mustacchi 		warn("failed to duplicate manual name for %s", map->cmap_name);
5487e3dbbacSRobert Mustacchi 		return (B_FALSE);
5497e3dbbacSRobert Mustacchi 	}
5507e3dbbacSRobert Mustacchi 
5517e3dbbacSRobert Mustacchi 	for (i = 0; upper[i] != '\0'; i++) {
5527e3dbbacSRobert Mustacchi 		upper[i] = toupper(upper[i]);
5537e3dbbacSRobert Mustacchi 	}
5547e3dbbacSRobert Mustacchi 
5557e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_manual_header, map->cmap_path, upper,
5567e3dbbacSRobert Mustacchi 	    map->cmap_name) == -1) {
5577e3dbbacSRobert Mustacchi 		warn("failed to write out manual header for %s",
5587e3dbbacSRobert Mustacchi 		    map->cmap_name);
5597e3dbbacSRobert Mustacchi 		free(upper);
5607e3dbbacSRobert Mustacchi 		return (B_FALSE);
5617e3dbbacSRobert Mustacchi 	}
5627e3dbbacSRobert Mustacchi 
5637e3dbbacSRobert Mustacchi 	for (proc = map->cmap_procs; proc != NULL; proc = proc->cproc_next) {
5647e3dbbacSRobert Mustacchi 		if (fprintf(f, ".It\n.Sy Family 0x%x, Model 0x%x\n",
5657e3dbbacSRobert Mustacchi 		    proc->cproc_family, proc->cproc_model) == -1) {
5667e3dbbacSRobert Mustacchi 			warn("failed to write out model information for %s",
5677e3dbbacSRobert Mustacchi 			    map->cmap_name);
5687e3dbbacSRobert Mustacchi 			free(upper);
5697e3dbbacSRobert Mustacchi 			return (B_FALSE);
5707e3dbbacSRobert Mustacchi 		}
5717e3dbbacSRobert Mustacchi 	}
5727e3dbbacSRobert Mustacchi 
5737e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_manual_data, map->cmap_path, upper,
5747e3dbbacSRobert Mustacchi 	    map->cmap_name) == -1) {
5757e3dbbacSRobert Mustacchi 		warn("failed to write out manual header for %s",
5767e3dbbacSRobert Mustacchi 		    map->cmap_name);
5777e3dbbacSRobert Mustacchi 		free(upper);
5787e3dbbacSRobert Mustacchi 		return (B_FALSE);
5797e3dbbacSRobert Mustacchi 	}
5807e3dbbacSRobert Mustacchi 
5817e3dbbacSRobert Mustacchi 	free(upper);
5827e3dbbacSRobert Mustacchi 	return (B_TRUE);
5837e3dbbacSRobert Mustacchi }
5847e3dbbacSRobert Mustacchi 
5857e3dbbacSRobert Mustacchi static boolean_t
5867e3dbbacSRobert Mustacchi cpcgen_manual_file_after(FILE *f, cpc_map_t *map)
5877e3dbbacSRobert Mustacchi {
5887e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_manual_trailer) == -1) {
5897e3dbbacSRobert Mustacchi 		warn("failed to write out manual header for %s",
5907e3dbbacSRobert Mustacchi 		    map->cmap_name);
5917e3dbbacSRobert Mustacchi 		return (B_FALSE);
5927e3dbbacSRobert Mustacchi 	}
5937e3dbbacSRobert Mustacchi 
5947e3dbbacSRobert Mustacchi 	return (B_TRUE);
5957e3dbbacSRobert Mustacchi }
5967e3dbbacSRobert Mustacchi 
5977e3dbbacSRobert Mustacchi static boolean_t
5987e3dbbacSRobert Mustacchi cpcgen_manual_event(FILE *f, nvlist_t *nvl, const char *path, uint32_t ent)
5997e3dbbacSRobert Mustacchi {
6007e3dbbacSRobert Mustacchi 	char *event, *lname, *brief = NULL, *public = NULL, *errata = NULL;
6017e3dbbacSRobert Mustacchi 	size_t i;
6027e3dbbacSRobert Mustacchi 
6037e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
6047e3dbbacSRobert Mustacchi 		warnx("Found event without 'EventName' property "
6057e3dbbacSRobert Mustacchi 		    "in %s, entry %u", path, ent);
6067e3dbbacSRobert Mustacchi 		return (B_FALSE);
6077e3dbbacSRobert Mustacchi 	}
6087e3dbbacSRobert Mustacchi 
6097e3dbbacSRobert Mustacchi 	/*
6107e3dbbacSRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
6117e3dbbacSRobert Mustacchi 	 */
6127e3dbbacSRobert Mustacchi 	if ((lname = strdup(event)) == NULL) {
6137e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", event);
6147e3dbbacSRobert Mustacchi 	}
6157e3dbbacSRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
6167e3dbbacSRobert Mustacchi 		lname[i] = tolower(event[i]);
6177e3dbbacSRobert Mustacchi 	}
6187e3dbbacSRobert Mustacchi 
6197e3dbbacSRobert Mustacchi 	/*
6207e3dbbacSRobert Mustacchi 	 * Try to get the other event fields, but if they're not there, don't
6217e3dbbacSRobert Mustacchi 	 * worry about it.
6227e3dbbacSRobert Mustacchi 	 */
6237e3dbbacSRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "BriefDescription", &brief);
6247e3dbbacSRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "PublicDescription", &public);
6257e3dbbacSRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "Errata", &errata);
6267e3dbbacSRobert Mustacchi 	if (errata != NULL && (strcmp(errata, "0") == 0 ||
6277e3dbbacSRobert Mustacchi 	    strcmp(errata, "null") == 0)) {
6287e3dbbacSRobert Mustacchi 		errata = NULL;
6297e3dbbacSRobert Mustacchi 	}
6307e3dbbacSRobert Mustacchi 
6317e3dbbacSRobert Mustacchi 	if (fprintf(f, ".It Sy %s\n", lname) == -1) {
6327e3dbbacSRobert Mustacchi 		warn("failed to write out probe entry %s", event);
6337e3dbbacSRobert Mustacchi 		free(lname);
6347e3dbbacSRobert Mustacchi 		return (B_FALSE);
6357e3dbbacSRobert Mustacchi 	}
6367e3dbbacSRobert Mustacchi 
6377e3dbbacSRobert Mustacchi 	if (public != NULL) {
6387e3dbbacSRobert Mustacchi 		if (fprintf(f, "%s\n", public) == -1) {
6397e3dbbacSRobert Mustacchi 			warn("failed to write out probe entry %s", event);
6407e3dbbacSRobert Mustacchi 			free(lname);
6417e3dbbacSRobert Mustacchi 			return (B_FALSE);
6427e3dbbacSRobert Mustacchi 		}
6437e3dbbacSRobert Mustacchi 	} else if (brief != NULL) {
6447e3dbbacSRobert Mustacchi 		if (fprintf(f, "%s\n", brief) == -1) {
6457e3dbbacSRobert Mustacchi 			warn("failed to write out probe entry %s", event);
6467e3dbbacSRobert Mustacchi 			free(lname);
6477e3dbbacSRobert Mustacchi 			return (B_FALSE);
6487e3dbbacSRobert Mustacchi 		}
6497e3dbbacSRobert Mustacchi 	}
6507e3dbbacSRobert Mustacchi 
6517e3dbbacSRobert Mustacchi 	if (errata != NULL) {
6527e3dbbacSRobert Mustacchi 		if (fprintf(f, ".Pp\nThe following errata may apply to this: "
6537e3dbbacSRobert Mustacchi 		    "%s\n", errata) == -1) {
6547e3dbbacSRobert Mustacchi 
6557e3dbbacSRobert Mustacchi 			warn("failed to write out probe entry %s", event);
6567e3dbbacSRobert Mustacchi 			free(lname);
6577e3dbbacSRobert Mustacchi 			return (B_FALSE);
6587e3dbbacSRobert Mustacchi 		}
6597e3dbbacSRobert Mustacchi 	}
6607e3dbbacSRobert Mustacchi 
6617e3dbbacSRobert Mustacchi 	free(lname);
6627e3dbbacSRobert Mustacchi 	return (B_TRUE);
6637e3dbbacSRobert Mustacchi }
6647e3dbbacSRobert Mustacchi 
6657e3dbbacSRobert Mustacchi static char *
6667e3dbbacSRobert Mustacchi cpcgen_cfile_name(cpc_map_t *map)
6677e3dbbacSRobert Mustacchi {
6687e3dbbacSRobert Mustacchi 	char *name;
6697e3dbbacSRobert Mustacchi 
6707e3dbbacSRobert Mustacchi 	if (asprintf(&name, "core_pcbe_%s.c", map->cmap_name) == -1) {
6717e3dbbacSRobert Mustacchi 		warn("failed to assemble file name for %s", map->cmap_path);
6727e3dbbacSRobert Mustacchi 		return (NULL);
6737e3dbbacSRobert Mustacchi 	}
6747e3dbbacSRobert Mustacchi 
6757e3dbbacSRobert Mustacchi 	return (name);
6767e3dbbacSRobert Mustacchi }
6777e3dbbacSRobert Mustacchi 
6787e3dbbacSRobert Mustacchi static boolean_t
6797e3dbbacSRobert Mustacchi cpcgen_cfile_file_before(FILE *f, cpc_map_t *map)
6807e3dbbacSRobert Mustacchi {
6817e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, map->cmap_path) == -1) {
6827e3dbbacSRobert Mustacchi 		warn("failed to write header to temporary file for %s",
6837e3dbbacSRobert Mustacchi 		    map->cmap_path);
6847e3dbbacSRobert Mustacchi 		return (B_FALSE);
6857e3dbbacSRobert Mustacchi 	}
6867e3dbbacSRobert Mustacchi 
6877e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_table_start, map->cmap_name) == -1) {
6887e3dbbacSRobert Mustacchi 		warn("failed to write header to temporary file for %s",
6897e3dbbacSRobert Mustacchi 		    map->cmap_path);
6907e3dbbacSRobert Mustacchi 		return (B_FALSE);
6917e3dbbacSRobert Mustacchi 	}
6927e3dbbacSRobert Mustacchi 
6937e3dbbacSRobert Mustacchi 	return (B_TRUE);
6947e3dbbacSRobert Mustacchi }
6957e3dbbacSRobert Mustacchi 
6967e3dbbacSRobert Mustacchi static boolean_t
6977e3dbbacSRobert Mustacchi cpcgen_cfile_file_after(FILE *f, cpc_map_t *map)
6987e3dbbacSRobert Mustacchi {
6997e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_table_end) == -1) {
7007e3dbbacSRobert Mustacchi 		warn("failed to write footer to temporary file for %s",
7017e3dbbacSRobert Mustacchi 		    map->cmap_path);
7027e3dbbacSRobert Mustacchi 		return (B_FALSE);
7037e3dbbacSRobert Mustacchi 	}
7047e3dbbacSRobert Mustacchi 
7057e3dbbacSRobert Mustacchi 	return (B_TRUE);
7067e3dbbacSRobert Mustacchi }
7077e3dbbacSRobert Mustacchi 
7087e3dbbacSRobert Mustacchi static boolean_t
7097e3dbbacSRobert Mustacchi cpcgen_cfile_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent)
7107e3dbbacSRobert Mustacchi {
7117e3dbbacSRobert Mustacchi 	char *ecode, *umask, *name, *counter, *lname, *cmask;
7127e3dbbacSRobert Mustacchi 	size_t i;
7137e3dbbacSRobert Mustacchi 
7147e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &name) != 0) {
7157e3dbbacSRobert Mustacchi 		warnx("Found event without 'EventName' property "
7167e3dbbacSRobert Mustacchi 		    "in %s, entry %u", path, ent);
7177e3dbbacSRobert Mustacchi 		return (B_FALSE);
7187e3dbbacSRobert Mustacchi 	}
7197e3dbbacSRobert Mustacchi 
7207e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
7217e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
7227e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0) {
7237e3dbbacSRobert Mustacchi 		warnx("event %s (index %u) from %s, missing "
7247e3dbbacSRobert Mustacchi 		    "required properties for C file translation",
7257e3dbbacSRobert Mustacchi 		    name, ent, path);
7267e3dbbacSRobert Mustacchi 		return (B_FALSE);
7277e3dbbacSRobert Mustacchi 	}
7287e3dbbacSRobert Mustacchi 
7297e3dbbacSRobert Mustacchi 	/*
7307e3dbbacSRobert Mustacchi 	 * While we could try and parse the counters manually, just do this the
7317e3dbbacSRobert Mustacchi 	 * max power way for now based on all possible values.
7327e3dbbacSRobert Mustacchi 	 */
7337e3dbbacSRobert Mustacchi 	if (strcmp(counter, "0") == 0 || strcmp(counter, "0,") == 0) {
7347e3dbbacSRobert Mustacchi 		cmask = "C0";
7357e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "1") == 0) {
7367e3dbbacSRobert Mustacchi 		cmask = "C1";
7377e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "2") == 0) {
7387e3dbbacSRobert Mustacchi 		cmask = "C2";
7397e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "3") == 0) {
7407e3dbbacSRobert Mustacchi 		cmask = "C3";
7417e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,1") == 0) {
7427e3dbbacSRobert Mustacchi 		cmask = "C0|C1";
7437e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,1,2") == 0) {
7447e3dbbacSRobert Mustacchi 		cmask = "C0|C1|C2";
7457e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,1,2,3") == 0) {
7467e3dbbacSRobert Mustacchi 		cmask = "C0|C1|C2|C3";
7477e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,2,3") == 0) {
7487e3dbbacSRobert Mustacchi 		cmask = "C0|C2|C3";
7497e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "1,2,3") == 0) {
7507e3dbbacSRobert Mustacchi 		cmask = "C1|C2|C3";
7517e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "2,3") == 0) {
7527e3dbbacSRobert Mustacchi 		cmask = "C2|C3";
7537e3dbbacSRobert Mustacchi 	} else {
7547e3dbbacSRobert Mustacchi 		warnx("event %s (index %u) from %s, has unknown "
7557e3dbbacSRobert Mustacchi 		    "counter value \"%s\"", name, ent, path, counter);
7567e3dbbacSRobert Mustacchi 		return (B_FALSE);
7577e3dbbacSRobert Mustacchi 	}
7587e3dbbacSRobert Mustacchi 
7597e3dbbacSRobert Mustacchi 
7607e3dbbacSRobert Mustacchi 	/*
7617e3dbbacSRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
7627e3dbbacSRobert Mustacchi 	 */
7637e3dbbacSRobert Mustacchi 	if ((lname = strdup(name)) == NULL) {
7647e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", name);
7657e3dbbacSRobert Mustacchi 	}
7667e3dbbacSRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
7677e3dbbacSRobert Mustacchi 		lname[i] = tolower(name[i]);
7687e3dbbacSRobert Mustacchi 	}
7697e3dbbacSRobert Mustacchi 
7707e3dbbacSRobert Mustacchi 	if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, cmask,
7717e3dbbacSRobert Mustacchi 	    lname) == -1) {
7727e3dbbacSRobert Mustacchi 		warn("failed to write out entry %s from %s", name, path);
7737e3dbbacSRobert Mustacchi 		free(lname);
7747e3dbbacSRobert Mustacchi 		return (B_FALSE);
7757e3dbbacSRobert Mustacchi 	}
7767e3dbbacSRobert Mustacchi 
7777e3dbbacSRobert Mustacchi 	free(lname);
7787e3dbbacSRobert Mustacchi 
7797e3dbbacSRobert Mustacchi 	/*
7807e3dbbacSRobert Mustacchi 	 * Check if we have any PAPI aliases.
7817e3dbbacSRobert Mustacchi 	 */
7827e3dbbacSRobert Mustacchi 	for (i = 0; cpcgen_papi_map[i].cpapi_intc != NULL; i++) {
7837e3dbbacSRobert Mustacchi 		if (strcmp(name, cpcgen_papi_map[i].cpapi_intc) != 0)
7847e3dbbacSRobert Mustacchi 			continue;
7857e3dbbacSRobert Mustacchi 
7867e3dbbacSRobert Mustacchi 		if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask,
7877e3dbbacSRobert Mustacchi 		    cmask, cpcgen_papi_map[i].cpapi_papi) == -1) {
7887e3dbbacSRobert Mustacchi 			warn("failed to write out entry %s from %s", name,
7897e3dbbacSRobert Mustacchi 			    path);
7907e3dbbacSRobert Mustacchi 			return (B_FALSE);
7917e3dbbacSRobert Mustacchi 		}
7927e3dbbacSRobert Mustacchi 	}
7937e3dbbacSRobert Mustacchi 
7947e3dbbacSRobert Mustacchi 	return (B_TRUE);
7957e3dbbacSRobert Mustacchi }
7967e3dbbacSRobert Mustacchi 
7977e3dbbacSRobert Mustacchi /*
7987e3dbbacSRobert Mustacchi  * Generate a header file that declares all of these arrays and provide a map
7997e3dbbacSRobert Mustacchi  * for models to the corresponding table to use.
8007e3dbbacSRobert Mustacchi  */
8017e3dbbacSRobert Mustacchi static void
8027e3dbbacSRobert Mustacchi cpcgen_common_files(int dirfd)
8037e3dbbacSRobert Mustacchi {
8047e3dbbacSRobert Mustacchi 	const char *fname = "core_pcbe_cpcgen.h";
8057e3dbbacSRobert Mustacchi 	char *tmpname;
8067e3dbbacSRobert Mustacchi 	int fd;
8077e3dbbacSRobert Mustacchi 	FILE *f;
8087e3dbbacSRobert Mustacchi 	cpc_map_t *map;
8097e3dbbacSRobert Mustacchi 
8107e3dbbacSRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
8117e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
8127e3dbbacSRobert Mustacchi 	}
8137e3dbbacSRobert Mustacchi 
8147e3dbbacSRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
8157e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
8167e3dbbacSRobert Mustacchi 		    tmpname);
8177e3dbbacSRobert Mustacchi 	}
8187e3dbbacSRobert Mustacchi 
8197e3dbbacSRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
8207e3dbbacSRobert Mustacchi 		int e = errno;
8217e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
8227e3dbbacSRobert Mustacchi 		errno = e;
8237e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
8247e3dbbacSRobert Mustacchi 	}
8257e3dbbacSRobert Mustacchi 
8267e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) {
8277e3dbbacSRobert Mustacchi 		int e = errno;
8287e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
8297e3dbbacSRobert Mustacchi 		errno = e;
8307e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
8317e3dbbacSRobert Mustacchi 		    "for %s", fname);
8327e3dbbacSRobert Mustacchi 	}
8337e3dbbacSRobert Mustacchi 
8347e3dbbacSRobert Mustacchi 	if (fprintf(f, "#ifndef _CORE_PCBE_CPCGEN_H\n"
8357e3dbbacSRobert Mustacchi 	    "#define\t_CORE_PCBE_CPCGEN_H\n"
8367e3dbbacSRobert Mustacchi 	    "\n"
8377e3dbbacSRobert Mustacchi 	    "#ifdef __cplusplus\n"
8387e3dbbacSRobert Mustacchi 	    "extern \"C\" {\n"
8397e3dbbacSRobert Mustacchi 	    "#endif\n"
8407e3dbbacSRobert Mustacchi 	    "\n"
8417e3dbbacSRobert Mustacchi 	    "extern const struct events_table_t *core_cpcgen_table(uint_t);\n"
8427e3dbbacSRobert Mustacchi 	    "\n") == -1) {
8437e3dbbacSRobert Mustacchi 		int e = errno;
8447e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
8457e3dbbacSRobert Mustacchi 		errno = e;
8467e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
8477e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
8487e3dbbacSRobert Mustacchi 	}
8497e3dbbacSRobert Mustacchi 
8507e3dbbacSRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
8517e3dbbacSRobert Mustacchi 		if (fprintf(f, "extern const struct events_table_t "
8527e3dbbacSRobert Mustacchi 		    "pcbe_core_events_%s[];\n", map->cmap_name) == -1) {
8537e3dbbacSRobert Mustacchi 			int e = errno;
8547e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
8557e3dbbacSRobert Mustacchi 			errno = e;
8567e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write entry to "
8577e3dbbacSRobert Mustacchi 			    "temporary file for %s", fname);
8587e3dbbacSRobert Mustacchi 		}
8597e3dbbacSRobert Mustacchi 	}
8607e3dbbacSRobert Mustacchi 
8617e3dbbacSRobert Mustacchi 	if (fprintf(f, "\n"
8627e3dbbacSRobert Mustacchi 	    "#ifdef __cplusplus\n"
8637e3dbbacSRobert Mustacchi 	    "}\n"
8647e3dbbacSRobert Mustacchi 	    "#endif\n"
8657e3dbbacSRobert Mustacchi 	    "\n"
8667e3dbbacSRobert Mustacchi 	    "#endif /* _CORE_PCBE_CPCGEN_H */\n") == -1) {
8677e3dbbacSRobert Mustacchi 		int e = errno;
8687e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
8697e3dbbacSRobert Mustacchi 		errno = e;
8707e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
8717e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
8727e3dbbacSRobert Mustacchi 	}
8737e3dbbacSRobert Mustacchi 
8747e3dbbacSRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
8757e3dbbacSRobert Mustacchi 		int e = errno;
8767e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
8777e3dbbacSRobert Mustacchi 		errno = e;
8787e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
8797e3dbbacSRobert Mustacchi 	}
8807e3dbbacSRobert Mustacchi 
8817e3dbbacSRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
8827e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
8837e3dbbacSRobert Mustacchi 		    tmpname);
8847e3dbbacSRobert Mustacchi 	}
8857e3dbbacSRobert Mustacchi 
8867e3dbbacSRobert Mustacchi 	free(tmpname);
8877e3dbbacSRobert Mustacchi 
8887e3dbbacSRobert Mustacchi 	/* Now again for the .c file. */
8897e3dbbacSRobert Mustacchi 	fname = "core_pcbe_cpcgen.c";
8907e3dbbacSRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
8917e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
8927e3dbbacSRobert Mustacchi 	}
8937e3dbbacSRobert Mustacchi 
8947e3dbbacSRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
8957e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
8967e3dbbacSRobert Mustacchi 		    tmpname);
8977e3dbbacSRobert Mustacchi 	}
8987e3dbbacSRobert Mustacchi 
8997e3dbbacSRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
9007e3dbbacSRobert Mustacchi 		int e = errno;
9017e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
9027e3dbbacSRobert Mustacchi 		errno = e;
9037e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
9047e3dbbacSRobert Mustacchi 	}
9057e3dbbacSRobert Mustacchi 
9067e3dbbacSRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) {
9077e3dbbacSRobert Mustacchi 		int e = errno;
9087e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
9097e3dbbacSRobert Mustacchi 		errno = e;
9107e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
9117e3dbbacSRobert Mustacchi 		    "for %s", fname);
9127e3dbbacSRobert Mustacchi 	}
9137e3dbbacSRobert Mustacchi 
9147e3dbbacSRobert Mustacchi 	if (fprintf(f, "#include <core_pcbe_table.h>\n"
9157e3dbbacSRobert Mustacchi 	    "#include <sys/null.h>\n"
9167e3dbbacSRobert Mustacchi 	    "#include \"core_pcbe_cpcgen.h\"\n"
9177e3dbbacSRobert Mustacchi 	    "\n"
9187e3dbbacSRobert Mustacchi 	    "const struct events_table_t *\n"
9197e3dbbacSRobert Mustacchi 	    "core_cpcgen_table(uint_t model)\n"
9207e3dbbacSRobert Mustacchi 	    "{\n"
9217e3dbbacSRobert Mustacchi 	    "\tswitch (model) {\n") == -1) {
9227e3dbbacSRobert Mustacchi 		int e = errno;
9237e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
9247e3dbbacSRobert Mustacchi 		errno = e;
9257e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
9267e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
9277e3dbbacSRobert Mustacchi 	}
9287e3dbbacSRobert Mustacchi 
9297e3dbbacSRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
9307e3dbbacSRobert Mustacchi 		cpc_proc_t *p;
9317e3dbbacSRobert Mustacchi 		for (p = map->cmap_procs; p != NULL; p = p->cproc_next) {
9327e3dbbacSRobert Mustacchi 			assert(p->cproc_family == 6);
9337e3dbbacSRobert Mustacchi 			if (fprintf(f, "\t\tcase 0x%x:\n", p->cproc_model) ==
9347e3dbbacSRobert Mustacchi 			    -1) {
9357e3dbbacSRobert Mustacchi 				int e = errno;
9367e3dbbacSRobert Mustacchi 				(void) unlinkat(dirfd, tmpname, 0);
9377e3dbbacSRobert Mustacchi 				errno = e;
9387e3dbbacSRobert Mustacchi 				errx(EXIT_FAILURE, "failed to write header to "
9397e3dbbacSRobert Mustacchi 				    "temporary file for %s", fname);
9407e3dbbacSRobert Mustacchi 			}
9417e3dbbacSRobert Mustacchi 		}
9427e3dbbacSRobert Mustacchi 		if (fprintf(f, "\t\t\treturn (pcbe_core_events_%s);\n",
9437e3dbbacSRobert Mustacchi 		    map->cmap_name) == -1) {
9447e3dbbacSRobert Mustacchi 			int e = errno;
9457e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
9467e3dbbacSRobert Mustacchi 			errno = e;
9477e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write entry to "
9487e3dbbacSRobert Mustacchi 			    "temporary file for %s", fname);
9497e3dbbacSRobert Mustacchi 		}
9507e3dbbacSRobert Mustacchi 	}
9517e3dbbacSRobert Mustacchi 
9527e3dbbacSRobert Mustacchi 	if (fprintf(f, "\t\tdefault:\n"
9537e3dbbacSRobert Mustacchi 	    "\t\t\treturn (NULL);\n"
9547e3dbbacSRobert Mustacchi 	    "\t}\n"
9557e3dbbacSRobert Mustacchi 	    "}\n") == -1) {
9567e3dbbacSRobert Mustacchi 		int e = errno;
9577e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
9587e3dbbacSRobert Mustacchi 		errno = e;
9597e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
9607e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
9617e3dbbacSRobert Mustacchi 	}
9627e3dbbacSRobert Mustacchi 
9637e3dbbacSRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
9647e3dbbacSRobert Mustacchi 		int e = errno;
9657e3dbbacSRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
9667e3dbbacSRobert Mustacchi 		errno = e;
9677e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
9687e3dbbacSRobert Mustacchi 	}
9697e3dbbacSRobert Mustacchi 
9707e3dbbacSRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
9717e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
9727e3dbbacSRobert Mustacchi 		    tmpname);
9737e3dbbacSRobert Mustacchi 	}
9747e3dbbacSRobert Mustacchi 
9757e3dbbacSRobert Mustacchi 	free(tmpname);
9767e3dbbacSRobert Mustacchi }
9777e3dbbacSRobert Mustacchi 
9787e3dbbacSRobert Mustacchi /*
9797e3dbbacSRobert Mustacchi  * Look at a rule to determine whether or not we should consider including it or
9807e3dbbacSRobert Mustacchi  * not. At this point we've already filtered things such that we only get core
9817e3dbbacSRobert Mustacchi  * events.
9827e3dbbacSRobert Mustacchi  *
9837e3dbbacSRobert Mustacchi  * To consider an entry, we currently apply the following criteria:
9847e3dbbacSRobert Mustacchi  *
9857e3dbbacSRobert Mustacchi  * - The MSRIndex and MSRValue are zero. Programming additional MSRs is no
9867e3dbbacSRobert Mustacchi  *   supported right now.
9877e3dbbacSRobert Mustacchi  * - TakenAlone is non-zero, which means that it cannot run at the same time as
9887e3dbbacSRobert Mustacchi  *   another field.
9897e3dbbacSRobert Mustacchi  * - Offcore is one, indicating that it is off the core and we need to figure
9907e3dbbacSRobert Mustacchi  *   out if we can support this.
9917e3dbbacSRobert Mustacchi  * - If the counter is fixed, don't use it for now.
9927e3dbbacSRobert Mustacchi  * - If more than one value is specified in the EventCode or UMask values
9937e3dbbacSRobert Mustacchi  */
9947e3dbbacSRobert Mustacchi static boolean_t
9957e3dbbacSRobert Mustacchi cpcgen_skip_entry(nvlist_t *nvl, const char *path, uint_t ent)
9967e3dbbacSRobert Mustacchi {
9977e3dbbacSRobert Mustacchi 	char *event, *msridx, *msrval, *taken, *offcore, *counter;
9987e3dbbacSRobert Mustacchi 	char *ecode, *umask;
9997e3dbbacSRobert Mustacchi 
10007e3dbbacSRobert Mustacchi 	/*
10017e3dbbacSRobert Mustacchi 	 * Require EventName, it's kind of useless without that.
10027e3dbbacSRobert Mustacchi 	 */
10037e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
10047e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "Found event without 'EventName' property "
10057e3dbbacSRobert Mustacchi 		    "in %s, entry %u", path, ent);
10067e3dbbacSRobert Mustacchi 	}
10077e3dbbacSRobert Mustacchi 
10087e3dbbacSRobert Mustacchi 	/*
10097e3dbbacSRobert Mustacchi 	 * If we can't find an expected value, whine about it.
10107e3dbbacSRobert Mustacchi 	 */
10117e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "MSRIndex", &msridx) != 0 ||
10127e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "MSRValue", &msrval) != 0 ||
10137e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0 ||
10147e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
10157e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
10167e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "Offcore", &offcore) != 0) {
10177e3dbbacSRobert Mustacchi 		warnx("Skipping event %s (index %u) from %s, missing required "
10187e3dbbacSRobert Mustacchi 		    "property", event, ent, path);
10197e3dbbacSRobert Mustacchi 		return (B_TRUE);
10207e3dbbacSRobert Mustacchi 	}
10217e3dbbacSRobert Mustacchi 
10227e3dbbacSRobert Mustacchi 	/*
10237e3dbbacSRobert Mustacchi 	 * MSRIndex and MSRvalue comes as either "0" or "0x00".
10247e3dbbacSRobert Mustacchi 	 */
10257e3dbbacSRobert Mustacchi 	if ((strcmp(msridx, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
10267e3dbbacSRobert Mustacchi 	    (strcmp(msrval, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
10277e3dbbacSRobert Mustacchi 	    strcmp(offcore, "0") != 0 || strchr(ecode, ',') != NULL ||
10287e3dbbacSRobert Mustacchi 	    strchr(umask, ',') != NULL) {
10297e3dbbacSRobert Mustacchi 		return (B_TRUE);
10307e3dbbacSRobert Mustacchi 	}
10317e3dbbacSRobert Mustacchi 
10327e3dbbacSRobert Mustacchi 	/*
10337e3dbbacSRobert Mustacchi 	 * Unfortunately, not everything actually has "TakenAlone". If it
10347e3dbbacSRobert Mustacchi 	 * doesn't, we assume that it doesn't have to be.
10357e3dbbacSRobert Mustacchi 	 */
10367e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "TakenAlone", &taken) == 0 &&
10377e3dbbacSRobert Mustacchi 	    strcmp(taken, "0") != 0) {
10387e3dbbacSRobert Mustacchi 		return (B_TRUE);
10397e3dbbacSRobert Mustacchi 	}
10407e3dbbacSRobert Mustacchi 
10417e3dbbacSRobert Mustacchi 
10427e3dbbacSRobert Mustacchi 	if (strncasecmp(counter, "fixed", strlen("fixed")) == 0)
10437e3dbbacSRobert Mustacchi 		return (B_TRUE);
10447e3dbbacSRobert Mustacchi 
10457e3dbbacSRobert Mustacchi 	return (B_FALSE);
10467e3dbbacSRobert Mustacchi }
10477e3dbbacSRobert Mustacchi 
10487e3dbbacSRobert Mustacchi /*
10497e3dbbacSRobert Mustacchi  * For each processor family, generate a data file that contains all of the
10507e3dbbacSRobert Mustacchi  * events that we support. Also generate a header that can be included that
10517e3dbbacSRobert Mustacchi  * declares all of the tables.
10527e3dbbacSRobert Mustacchi  */
10537e3dbbacSRobert Mustacchi static void
10547e3dbbacSRobert Mustacchi cpcgen_gen(int dirfd)
10557e3dbbacSRobert Mustacchi {
10567e3dbbacSRobert Mustacchi 	cpc_map_t *map = cpcgen_maps;
10577e3dbbacSRobert Mustacchi 
10587e3dbbacSRobert Mustacchi 	if (map == NULL) {
10597e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "no platforms found or matched");
10607e3dbbacSRobert Mustacchi 	}
10617e3dbbacSRobert Mustacchi 
10627e3dbbacSRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
10637e3dbbacSRobert Mustacchi 		int fd, ret;
10647e3dbbacSRobert Mustacchi 		FILE *f;
10657e3dbbacSRobert Mustacchi 		char *tmpname, *name;
10667e3dbbacSRobert Mustacchi 		uint32_t length, i;
10677e3dbbacSRobert Mustacchi 
10687e3dbbacSRobert Mustacchi 		if ((name = cpcgen_ops.cgen_op_name(map)) == NULL) {
10697e3dbbacSRobert Mustacchi 			exit(EXIT_FAILURE);
10707e3dbbacSRobert Mustacchi 		}
10717e3dbbacSRobert Mustacchi 
10727e3dbbacSRobert Mustacchi 		if (asprintf(&tmpname, ".%s.%d", name, getpid()) == -1) {
10737e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to construct temporary file "
10747e3dbbacSRobert Mustacchi 			    "name");
10757e3dbbacSRobert Mustacchi 		}
10767e3dbbacSRobert Mustacchi 
10777e3dbbacSRobert Mustacchi 		if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0444)) < 0) {
10787e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to create temporary file %s",
10797e3dbbacSRobert Mustacchi 			    tmpname);
10807e3dbbacSRobert Mustacchi 		}
10817e3dbbacSRobert Mustacchi 
10827e3dbbacSRobert Mustacchi 		if ((f = fdopen(fd, "w")) == NULL) {
10837e3dbbacSRobert Mustacchi 			int e = errno;
10847e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
10857e3dbbacSRobert Mustacchi 			errno = e;
10867e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to fdopen temporary file");
10877e3dbbacSRobert Mustacchi 		}
10887e3dbbacSRobert Mustacchi 
10897e3dbbacSRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_before(f, map)) {
10907e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
10917e3dbbacSRobert Mustacchi 			exit(EXIT_FAILURE);
10927e3dbbacSRobert Mustacchi 		}
10937e3dbbacSRobert Mustacchi 
10947e3dbbacSRobert Mustacchi 		/*
10957e3dbbacSRobert Mustacchi 		 * Iterate over array contents.
10967e3dbbacSRobert Mustacchi 		 */
10977e3dbbacSRobert Mustacchi 		if ((ret = nvlist_lookup_uint32(map->cmap_data, "length",
10987e3dbbacSRobert Mustacchi 		    &length)) != 0) {
10997e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "failed to look up length property "
11007e3dbbacSRobert Mustacchi 			    "in parsed data for %s: %s", map->cmap_path,
11017e3dbbacSRobert Mustacchi 			    strerror(ret));
11027e3dbbacSRobert Mustacchi 		}
11037e3dbbacSRobert Mustacchi 
11047e3dbbacSRobert Mustacchi 		for (i = 0; i < length; i++) {
11057e3dbbacSRobert Mustacchi 			nvlist_t *nvl;
11067e3dbbacSRobert Mustacchi 			char num[64];
11077e3dbbacSRobert Mustacchi 
11087e3dbbacSRobert Mustacchi 			(void) snprintf(num, sizeof (num), "%u", i);
11097e3dbbacSRobert Mustacchi 			if ((ret = nvlist_lookup_nvlist(map->cmap_data,
11107e3dbbacSRobert Mustacchi 			    num, &nvl)) != 0) {
11117e3dbbacSRobert Mustacchi 				errx(EXIT_FAILURE, "failed to look up array "
11127e3dbbacSRobert Mustacchi 				    "entry %u in parsed data for %s: %s", i,
11137e3dbbacSRobert Mustacchi 				    map->cmap_path, strerror(ret));
11147e3dbbacSRobert Mustacchi 			}
11157e3dbbacSRobert Mustacchi 
11167e3dbbacSRobert Mustacchi 			if (cpcgen_skip_entry(nvl, map->cmap_path, i))
11177e3dbbacSRobert Mustacchi 				continue;
11187e3dbbacSRobert Mustacchi 
11197e3dbbacSRobert Mustacchi 			if (!cpcgen_ops.cgen_op_event(f, nvl, map->cmap_path,
11207e3dbbacSRobert Mustacchi 			    i)) {
11217e3dbbacSRobert Mustacchi 				(void) unlinkat(dirfd, tmpname, 0);
11227e3dbbacSRobert Mustacchi 				exit(EXIT_FAILURE);
11237e3dbbacSRobert Mustacchi 			}
11247e3dbbacSRobert Mustacchi 		}
11257e3dbbacSRobert Mustacchi 
11267e3dbbacSRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_after(f, map)) {
11277e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
11287e3dbbacSRobert Mustacchi 			exit(EXIT_FAILURE);
11297e3dbbacSRobert Mustacchi 		}
11307e3dbbacSRobert Mustacchi 
11317e3dbbacSRobert Mustacchi 		if (fflush(f) != 0 || fclose(f) != 0) {
11327e3dbbacSRobert Mustacchi 			int e = errno;
11337e3dbbacSRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
11347e3dbbacSRobert Mustacchi 			errno = e;
11357e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to flush and close "
11367e3dbbacSRobert Mustacchi 			    "temporary file");
11377e3dbbacSRobert Mustacchi 		}
11387e3dbbacSRobert Mustacchi 
11397e3dbbacSRobert Mustacchi 		if (renameat(dirfd, tmpname, dirfd, name) != 0) {
11407e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to rename temporary file %s",
11417e3dbbacSRobert Mustacchi 			    tmpname);
11427e3dbbacSRobert Mustacchi 		}
11437e3dbbacSRobert Mustacchi 
11447e3dbbacSRobert Mustacchi 		free(name);
11457e3dbbacSRobert Mustacchi 		free(tmpname);
11467e3dbbacSRobert Mustacchi 	}
11477e3dbbacSRobert Mustacchi }
11487e3dbbacSRobert Mustacchi 
11497e3dbbacSRobert Mustacchi static void
11507e3dbbacSRobert Mustacchi cpcgen_usage(const char *fmt, ...)
11517e3dbbacSRobert Mustacchi {
11527e3dbbacSRobert Mustacchi 	if (fmt != NULL) {
11537e3dbbacSRobert Mustacchi 		va_list ap;
11547e3dbbacSRobert Mustacchi 
11557e3dbbacSRobert Mustacchi 		(void) fprintf(stderr, "%s: ", cpcgen_progname);
11567e3dbbacSRobert Mustacchi 		va_start(ap, fmt);
11577e3dbbacSRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
11587e3dbbacSRobert Mustacchi 		va_end(ap);
11597e3dbbacSRobert Mustacchi 	}
11607e3dbbacSRobert Mustacchi 
11617e3dbbacSRobert Mustacchi 	(void) fprintf(stderr, "Usage: %s -a|-p platform -c|-H|-m -d datadir "
11627e3dbbacSRobert Mustacchi 	    "-o outdir\n"
11637e3dbbacSRobert Mustacchi 	    "\n"
11647e3dbbacSRobert Mustacchi 	    "\t-a  generate data for all platforms\n"
11657e3dbbacSRobert Mustacchi 	    "\t-c  generate C file for CPC\n"
11667e3dbbacSRobert Mustacchi 	    "\t-d  specify the directory containt perfmon data\n"
11677e3dbbacSRobert Mustacchi 	    "\t-h  generate header file and common files\n"
11687e3dbbacSRobert Mustacchi 	    "\t-m  generate manual pages for CPC data\n"
11697e3dbbacSRobert Mustacchi 	    "\t-o  outut files in directory outdir\n"
11707e3dbbacSRobert Mustacchi 	    "\t-p  generate data for a specified platform\n",
11717e3dbbacSRobert Mustacchi 	    cpcgen_progname);
11727e3dbbacSRobert Mustacchi }
11737e3dbbacSRobert Mustacchi 
11747e3dbbacSRobert Mustacchi int
11757e3dbbacSRobert Mustacchi main(int argc, char *argv[])
11767e3dbbacSRobert Mustacchi {
11777e3dbbacSRobert Mustacchi 	int c, outdirfd;
11787e3dbbacSRobert Mustacchi 	boolean_t do_mpage = B_FALSE, do_cfile = B_FALSE, do_header = B_FALSE,
11797e3dbbacSRobert Mustacchi 	    do_all = B_FALSE;
11807e3dbbacSRobert Mustacchi 	const char *datadir = NULL, *outdir = NULL, *platform = NULL;
11817e3dbbacSRobert Mustacchi 	uint_t count = 0;
11827e3dbbacSRobert Mustacchi 
11837e3dbbacSRobert Mustacchi 	cpcgen_progname = basename(argv[0]);
11847e3dbbacSRobert Mustacchi 
11857e3dbbacSRobert Mustacchi 	while ((c = getopt(argc, argv, ":acd:hHmo:p:")) != -1) {
11867e3dbbacSRobert Mustacchi 		switch (c) {
11877e3dbbacSRobert Mustacchi 		case 'a':
11887e3dbbacSRobert Mustacchi 			do_all = B_TRUE;
11897e3dbbacSRobert Mustacchi 			break;
11907e3dbbacSRobert Mustacchi 		case 'c':
11917e3dbbacSRobert Mustacchi 			do_cfile = B_TRUE;
11927e3dbbacSRobert Mustacchi 			break;
11937e3dbbacSRobert Mustacchi 		case 'd':
11947e3dbbacSRobert Mustacchi 			datadir = optarg;
11957e3dbbacSRobert Mustacchi 			break;
11967e3dbbacSRobert Mustacchi 		case 'm':
11977e3dbbacSRobert Mustacchi 			do_mpage = B_TRUE;
11987e3dbbacSRobert Mustacchi 			break;
11997e3dbbacSRobert Mustacchi 		case 'H':
12007e3dbbacSRobert Mustacchi 			do_header = B_TRUE;
12017e3dbbacSRobert Mustacchi 			break;
12027e3dbbacSRobert Mustacchi 		case 'o':
12037e3dbbacSRobert Mustacchi 			outdir = optarg;
12047e3dbbacSRobert Mustacchi 			break;
12057e3dbbacSRobert Mustacchi 		case 'p':
12067e3dbbacSRobert Mustacchi 			platform = optarg;
12077e3dbbacSRobert Mustacchi 			break;
12087e3dbbacSRobert Mustacchi 		case ':':
12097e3dbbacSRobert Mustacchi 			cpcgen_usage("Option -%c requires an operand\n",
12107e3dbbacSRobert Mustacchi 			    optopt);
12117e3dbbacSRobert Mustacchi 			return (2);
12127e3dbbacSRobert Mustacchi 		case '?':
12137e3dbbacSRobert Mustacchi 			cpcgen_usage("Unknown option: -%c\n", optopt);
12147e3dbbacSRobert Mustacchi 			return (2);
12157e3dbbacSRobert Mustacchi 		case 'h':
12167e3dbbacSRobert Mustacchi 		default:
12177e3dbbacSRobert Mustacchi 			cpcgen_usage(NULL);
12187e3dbbacSRobert Mustacchi 			return (2);
12197e3dbbacSRobert Mustacchi 		}
12207e3dbbacSRobert Mustacchi 	}
12217e3dbbacSRobert Mustacchi 
12227e3dbbacSRobert Mustacchi 	count = 0;
12237e3dbbacSRobert Mustacchi 	if (do_mpage)
12247e3dbbacSRobert Mustacchi 		count++;
12257e3dbbacSRobert Mustacchi 	if (do_cfile)
12267e3dbbacSRobert Mustacchi 		count++;
12277e3dbbacSRobert Mustacchi 	if (do_header)
12287e3dbbacSRobert Mustacchi 		count++;
12297e3dbbacSRobert Mustacchi 	if (count > 1) {
12307e3dbbacSRobert Mustacchi 		cpcgen_usage("Only one of -c, -h, and -m may be specified\n");
12317e3dbbacSRobert Mustacchi 		return (2);
12327e3dbbacSRobert Mustacchi 	} else if (count == 0) {
12337e3dbbacSRobert Mustacchi 		cpcgen_usage("One of -c, -h, and -m is required\n");
12347e3dbbacSRobert Mustacchi 		return (2);
12357e3dbbacSRobert Mustacchi 	}
12367e3dbbacSRobert Mustacchi 
12377e3dbbacSRobert Mustacchi 	count = 0;
12387e3dbbacSRobert Mustacchi 	if (do_all)
12397e3dbbacSRobert Mustacchi 		count++;
12407e3dbbacSRobert Mustacchi 	if (platform != NULL)
12417e3dbbacSRobert Mustacchi 		count++;
12427e3dbbacSRobert Mustacchi 	if (count > 1) {
12437e3dbbacSRobert Mustacchi 		cpcgen_usage("Only one of -a and -p may be specified\n");
12447e3dbbacSRobert Mustacchi 		return (2);
12457e3dbbacSRobert Mustacchi 	} else if (count == 0) {
12467e3dbbacSRobert Mustacchi 		cpcgen_usage("One of -a and -p is required\n");
12477e3dbbacSRobert Mustacchi 		return (2);
12487e3dbbacSRobert Mustacchi 	}
12497e3dbbacSRobert Mustacchi 
12507e3dbbacSRobert Mustacchi 
12517e3dbbacSRobert Mustacchi 	if (outdir == NULL) {
12527e3dbbacSRobert Mustacchi 		cpcgen_usage("Missing required output directory (-o)\n");
12537e3dbbacSRobert Mustacchi 		return (2);
12547e3dbbacSRobert Mustacchi 	}
12557e3dbbacSRobert Mustacchi 
12567e3dbbacSRobert Mustacchi 	if ((outdirfd = open(outdir, O_RDONLY)) < 0) {
12577e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open output directory %s", outdir);
12587e3dbbacSRobert Mustacchi 	}
12597e3dbbacSRobert Mustacchi 
12607e3dbbacSRobert Mustacchi 	if (datadir == NULL) {
12617e3dbbacSRobert Mustacchi 		cpcgen_usage("Missing required data directory (-d)\n");
12627e3dbbacSRobert Mustacchi 		return (2);
12637e3dbbacSRobert Mustacchi 	}
12647e3dbbacSRobert Mustacchi 
12657e3dbbacSRobert Mustacchi 	cpcgen_read_mapfile(datadir, platform);
12667e3dbbacSRobert Mustacchi 
12677e3dbbacSRobert Mustacchi 	if (do_header) {
12687e3dbbacSRobert Mustacchi 		cpcgen_common_files(outdirfd);
12697e3dbbacSRobert Mustacchi 		return (0);
12707e3dbbacSRobert Mustacchi 	}
12717e3dbbacSRobert Mustacchi 
12727e3dbbacSRobert Mustacchi 	if (do_mpage) {
12737e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_name = cpcgen_manual_name;
12747e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_file_before = cpcgen_manual_file_before;
12757e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_file_after = cpcgen_manual_file_after;
12767e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_event = cpcgen_manual_event;
12777e3dbbacSRobert Mustacchi 	}
12787e3dbbacSRobert Mustacchi 
12797e3dbbacSRobert Mustacchi 	if (do_cfile) {
12807e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_name = cpcgen_cfile_name;
12817e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_file_before = cpcgen_cfile_file_before;
12827e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_file_after = cpcgen_cfile_file_after;
12837e3dbbacSRobert Mustacchi 		cpcgen_ops.cgen_op_event = cpcgen_cfile_event;
12847e3dbbacSRobert Mustacchi 	}
12857e3dbbacSRobert Mustacchi 
12867e3dbbacSRobert Mustacchi 
12877e3dbbacSRobert Mustacchi 	cpcgen_gen(outdirfd);
12887e3dbbacSRobert Mustacchi 
12897e3dbbacSRobert Mustacchi 	return (0);
12907e3dbbacSRobert Mustacchi }
1291