xref: /titanic_50/usr/src/tools/cpcgen/cpcgen.c (revision 5fc40de04b67592be50772c772ace24a75df2712)
153548f91SRobert Mustacchi /*
253548f91SRobert Mustacchi  * This file and its contents are supplied under the terms of the
353548f91SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
453548f91SRobert Mustacchi  * You may only use this file in accordance with the terms of version
553548f91SRobert Mustacchi  * 1.0 of the CDDL.
653548f91SRobert Mustacchi  *
753548f91SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
853548f91SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
953548f91SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
1053548f91SRobert Mustacchi  */
1153548f91SRobert Mustacchi 
1253548f91SRobert Mustacchi /*
131ad658abSJohn Levon  * Copyright (c) 2019, Joyent, Inc.
1453548f91SRobert Mustacchi  */
1553548f91SRobert Mustacchi 
1653548f91SRobert Mustacchi /*
1753548f91SRobert Mustacchi  * This file transforms the perfmon data files into C files and manual pages.
1853548f91SRobert Mustacchi  */
1953548f91SRobert Mustacchi 
2053548f91SRobert Mustacchi #include <stdio.h>
2153548f91SRobert Mustacchi #include <stdarg.h>
2253548f91SRobert Mustacchi #include <unistd.h>
2353548f91SRobert Mustacchi #include <err.h>
2453548f91SRobert Mustacchi #include <libgen.h>
2553548f91SRobert Mustacchi #include <libnvpair.h>
2653548f91SRobert Mustacchi #include <strings.h>
2753548f91SRobert Mustacchi #include <errno.h>
2853548f91SRobert Mustacchi #include <limits.h>
2953548f91SRobert Mustacchi #include <sys/mman.h>
3053548f91SRobert Mustacchi #include <sys/param.h>
3153548f91SRobert Mustacchi #include <assert.h>
3253548f91SRobert Mustacchi #include <ctype.h>
3353548f91SRobert Mustacchi #include <sys/types.h>
3453548f91SRobert Mustacchi #include <sys/stat.h>
3553548f91SRobert Mustacchi #include <fcntl.h>
3653548f91SRobert Mustacchi 
3753548f91SRobert Mustacchi #include <json_nvlist.h>
3853548f91SRobert Mustacchi 
3953548f91SRobert Mustacchi #define	EXIT_USAGE	2
40*5fc40de0SRobert Mustacchi #define	CPROC_MAX_STEPPINGS	16
4153548f91SRobert Mustacchi 
4253548f91SRobert Mustacchi typedef struct cpc_proc {
4353548f91SRobert Mustacchi 	struct cpc_proc *cproc_next;
4453548f91SRobert Mustacchi 	uint_t		cproc_family;
4553548f91SRobert Mustacchi 	uint_t		cproc_model;
46*5fc40de0SRobert Mustacchi 	uint_t		cproc_nsteps;
47*5fc40de0SRobert Mustacchi 	uint_t		cproc_steppings[CPROC_MAX_STEPPINGS];
4853548f91SRobert Mustacchi } cpc_proc_t;
4953548f91SRobert Mustacchi 
5053548f91SRobert Mustacchi typedef enum cpc_file_type {
5153548f91SRobert Mustacchi 	CPC_FILE_CORE		= 1 << 0,
5253548f91SRobert Mustacchi 	CPC_FILE_OFF_CORE	= 1 << 1,
5353548f91SRobert Mustacchi 	CPC_FILE_UNCORE		= 1 << 2,
5453548f91SRobert Mustacchi 	CPC_FILE_FP_MATH	= 1 << 3,
5553548f91SRobert Mustacchi 	CPC_FILE_UNCORE_EXP	= 1 << 4
5653548f91SRobert Mustacchi } cpc_type_t;
5753548f91SRobert Mustacchi 
5853548f91SRobert Mustacchi typedef struct cpc_map {
5953548f91SRobert Mustacchi 	struct cpc_map	*cmap_next;
6053548f91SRobert Mustacchi 	cpc_type_t	cmap_type;
6153548f91SRobert Mustacchi 	nvlist_t	*cmap_data;
6253548f91SRobert Mustacchi 	char		*cmap_path;
6353548f91SRobert Mustacchi 	const char	*cmap_name;
6453548f91SRobert Mustacchi 	cpc_proc_t	*cmap_procs;
6553548f91SRobert Mustacchi } cpc_map_t;
6653548f91SRobert Mustacchi 
6753548f91SRobert Mustacchi typedef struct cpc_whitelist {
6853548f91SRobert Mustacchi 	const char	*cwhite_short;
6953548f91SRobert Mustacchi 	const char	*cwhite_human;
7053548f91SRobert Mustacchi 	uint_t		cwhite_mask;
7153548f91SRobert Mustacchi } cpc_whitelist_t;
7253548f91SRobert Mustacchi 
7353548f91SRobert Mustacchi /*
7453548f91SRobert Mustacchi  * List of architectures that we support generating this data for. This is done
7553548f91SRobert Mustacchi  * so that processors that illumos doesn't support or run on aren't generated
7653548f91SRobert Mustacchi  * (generally the Xeon Phi).
7753548f91SRobert Mustacchi  */
7853548f91SRobert Mustacchi static cpc_whitelist_t cpcgen_whitelist[] = {
7953548f91SRobert Mustacchi 	/* Nehalem */
8053548f91SRobert Mustacchi 	{ "NHM-EP", "nhm_ep", CPC_FILE_CORE },
8153548f91SRobert Mustacchi 	{ "NHM-EX", "nhm_ex", CPC_FILE_CORE },
8253548f91SRobert Mustacchi 	/* Westmere */
8353548f91SRobert Mustacchi 	{ "WSM-EP-DP", "wsm_ep_dp", CPC_FILE_CORE },
8453548f91SRobert Mustacchi 	{ "WSM-EP-SP", "wsm_ep_sp", CPC_FILE_CORE },
8553548f91SRobert Mustacchi 	{ "WSM-EX", "wsm_ex", CPC_FILE_CORE },
8653548f91SRobert Mustacchi 	/* Sandy Bridge */
8753548f91SRobert Mustacchi 	{ "SNB", "snb", CPC_FILE_CORE },
8853548f91SRobert Mustacchi 	{ "JKT", "jkt", CPC_FILE_CORE },
8953548f91SRobert Mustacchi 	/* Ivy Bridge */
9053548f91SRobert Mustacchi 	{ "IVB", "ivb", CPC_FILE_CORE },
9153548f91SRobert Mustacchi 	{ "IVT", "ivt", CPC_FILE_CORE },
9253548f91SRobert Mustacchi 	/* Haswell */
9353548f91SRobert Mustacchi 	{ "HSW", "hsw", CPC_FILE_CORE },
9453548f91SRobert Mustacchi 	{ "HSX", "hsx", CPC_FILE_CORE },
9553548f91SRobert Mustacchi 	/* Broadwell */
9653548f91SRobert Mustacchi 	{ "BDW", "bdw", CPC_FILE_CORE },
9753548f91SRobert Mustacchi 	{ "BDW-DE", "bdw_de", CPC_FILE_CORE },
9853548f91SRobert Mustacchi 	{ "BDX", "bdx", CPC_FILE_CORE },
9953548f91SRobert Mustacchi 	/* Skylake */
10053548f91SRobert Mustacchi 	{ "SKL", "skl", CPC_FILE_CORE },
10153548f91SRobert Mustacchi 	{ "SKX", "skx", CPC_FILE_CORE },
102*5fc40de0SRobert Mustacchi 	/* Cascade Lake */
103*5fc40de0SRobert Mustacchi 	{ "CLX", "clx", CPC_FILE_CORE },
10453548f91SRobert Mustacchi 	/* Atom */
10553548f91SRobert Mustacchi 	{ "BNL", "bnl", CPC_FILE_CORE },
10653548f91SRobert Mustacchi 	{ "SLM", "slm", CPC_FILE_CORE },
10753548f91SRobert Mustacchi 	{ "GLM", "glm", CPC_FILE_CORE },
10853548f91SRobert Mustacchi 	{ "GLP", "glp", CPC_FILE_CORE },
10953548f91SRobert Mustacchi 	{ NULL }
11053548f91SRobert Mustacchi };
11153548f91SRobert Mustacchi 
11253548f91SRobert Mustacchi typedef struct cpc_papi {
11353548f91SRobert Mustacchi 	const char	*cpapi_intc;
11453548f91SRobert Mustacchi 	const char	*cpapi_papi;
11553548f91SRobert Mustacchi } cpc_papi_t;
11653548f91SRobert Mustacchi 
11753548f91SRobert Mustacchi /*
11853548f91SRobert Mustacchi  * This table maps events with an Intel specific name to the corresponding PAPI
119*5fc40de0SRobert Mustacchi  * name. There may be multiple Intel events which map to the same PAPI event.
12053548f91SRobert Mustacchi  * This is usually because different processors have different names for an
12153548f91SRobert Mustacchi  * event. We use the title as opposed to the event codes because those can
12253548f91SRobert Mustacchi  * change somewhat arbitrarily between processor generations.
12353548f91SRobert Mustacchi  */
12453548f91SRobert Mustacchi static cpc_papi_t cpcgen_papi_map[] = {
12553548f91SRobert Mustacchi 	{ "CPU_CLK_UNHALTED.THREAD_P", "PAPI_tot_cyc" },
12653548f91SRobert Mustacchi 	{ "INST_RETIRED.ANY_P", "PAPI_tot_ins" },
12753548f91SRobert Mustacchi 	{ "BR_INST_RETIRED.ALL_BRANCHES", "PAPI_br_ins" },
12853548f91SRobert Mustacchi 	{ "BR_MISP_RETIRED.ALL_BRANCHES", "PAPI_br_msp" },
12953548f91SRobert Mustacchi 	{ "BR_INST_RETIRED.CONDITIONAL", "PAPI_br_cn" },
13053548f91SRobert Mustacchi 	{ "CYCLE_ACTIVITY.CYCLES_L1D_MISS", "PAPI_l1_dcm" },
13153548f91SRobert Mustacchi 	{ "L1I.HITS", "PAPI_l1_ich" },
13253548f91SRobert Mustacchi 	{ "ICACHE.HIT", "PAPI_l1_ich" },
13353548f91SRobert Mustacchi 	{ "L1I.MISS", "PAPI_L1_icm" },
13453548f91SRobert Mustacchi 	{ "ICACHE.MISSES", "PAPI_l1_icm" },
13553548f91SRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_ica" },
13653548f91SRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_ica" },
13753548f91SRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_icr" },
13853548f91SRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_icr" },
13953548f91SRobert Mustacchi 	{ "L2_RQSTS.CODE_RD_MISS", "PAPI_l2_icm" },
14053548f91SRobert Mustacchi 	{ "L2_RQSTS.MISS", "PAPI_l2_tcm" },
14153548f91SRobert Mustacchi 	{ "ITLB_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_im" },
14253548f91SRobert Mustacchi 	{ "DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_dm" },
14353548f91SRobert Mustacchi 	{ "PAGE_WALKS.D_SIDE_WALKS", "PAPI_tlb_dm" },
14453548f91SRobert Mustacchi 	{ "PAGE_WALKS.I_SIDE_WALKS", "PAPI_tlb_im" },
14553548f91SRobert Mustacchi 	{ "PAGE_WALKS.WALKS", "PAPI_tlb_tl" },
14653548f91SRobert Mustacchi 	{ "INST_QUEUE_WRITES", "PAPI_tot_iis" },
14753548f91SRobert Mustacchi 	{ "MEM_INST_RETIRED.STORES" "PAPI_sr_ins" },
14853548f91SRobert Mustacchi 	{ "MEM_INST_RETIRED.LOADS" "PAPI_ld_ins" },
14953548f91SRobert Mustacchi 	{ NULL, NULL }
15053548f91SRobert Mustacchi };
15153548f91SRobert Mustacchi 
15253548f91SRobert Mustacchi typedef struct cpcgen_ops {
15353548f91SRobert Mustacchi 	char *(*cgen_op_name)(cpc_map_t *);
15453548f91SRobert Mustacchi 	boolean_t (*cgen_op_file_before)(FILE *, cpc_map_t *);
15553548f91SRobert Mustacchi 	boolean_t (*cgen_op_file_after)(FILE *, cpc_map_t *);
15653548f91SRobert Mustacchi 	boolean_t (*cgen_op_event)(FILE *, nvlist_t *, const char *, uint32_t);
15753548f91SRobert Mustacchi } cpcgen_ops_t;
15853548f91SRobert Mustacchi 
15953548f91SRobert Mustacchi static cpcgen_ops_t cpcgen_ops;
16053548f91SRobert Mustacchi static const char *cpcgen_mapfile = "/mapfile.csv";
16153548f91SRobert Mustacchi static const char *cpcgen_progname;
16253548f91SRobert Mustacchi static cpc_map_t *cpcgen_maps;
16353548f91SRobert Mustacchi 
16453548f91SRobert Mustacchi /*
16553548f91SRobert Mustacchi  * Constants used for generating data.
16653548f91SRobert Mustacchi  */
16753548f91SRobert Mustacchi /* BEGIN CSTYLED */
16853548f91SRobert Mustacchi static const char *cpcgen_cfile_header = ""
16953548f91SRobert Mustacchi "/*\n"
17053548f91SRobert Mustacchi " *  Copyright (c) 2018, Intel Corporation\n"
17153548f91SRobert Mustacchi " *  Copyright (c) 2018, Joyent, Inc\n"
17253548f91SRobert Mustacchi " *  All rights reserved.\n"
17353548f91SRobert Mustacchi " *\n"
17453548f91SRobert Mustacchi " *  Redistribution and use in source and binary forms, with or without\n"
17553548f91SRobert Mustacchi " *  modification, are permitted provided that the following conditions are met:\n"
17653548f91SRobert Mustacchi " * \n"
17753548f91SRobert Mustacchi " *   1. Redistributions of source code must retain the above copyright notice,\n"
17853548f91SRobert Mustacchi " *      this list of conditions and the following disclaimer.\n"
17953548f91SRobert Mustacchi " * \n"
18053548f91SRobert Mustacchi " *   2. Redistributions in binary form must reproduce the above copyright \n"
18153548f91SRobert Mustacchi " *      notice, this list of conditions and the following disclaimer in the\n"
18253548f91SRobert Mustacchi " *      documentation and/or other materials provided with the distribution.\n"
18353548f91SRobert Mustacchi " * \n"
18453548f91SRobert Mustacchi " *   3. Neither the name of the Intel Corporation nor the names of its \n"
18553548f91SRobert Mustacchi " *      contributors may be used to endorse or promote products derived from\n"
18653548f91SRobert Mustacchi " *      this software without specific prior written permission.\n"
18753548f91SRobert Mustacchi " *\n"
18853548f91SRobert Mustacchi " *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
18953548f91SRobert Mustacchi " *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
19053548f91SRobert Mustacchi " *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
19153548f91SRobert Mustacchi " *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
19253548f91SRobert Mustacchi " *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
19353548f91SRobert Mustacchi " *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
19453548f91SRobert Mustacchi " *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
19553548f91SRobert Mustacchi " *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
19653548f91SRobert Mustacchi " *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
19753548f91SRobert Mustacchi " *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
19853548f91SRobert Mustacchi " *  POSSIBILITY OF SUCH DAMAGE.\n"
19953548f91SRobert Mustacchi " *\n"
20053548f91SRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n"
20153548f91SRobert Mustacchi " * data/perfmon%s\n"
20253548f91SRobert Mustacchi " *\n"
20353548f91SRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
20453548f91SRobert Mustacchi " */\n"
20553548f91SRobert Mustacchi "\n";
20653548f91SRobert Mustacchi /* END CSTYLED */
20753548f91SRobert Mustacchi 
20853548f91SRobert Mustacchi static const char *cpcgen_cfile_table_start = ""
20953548f91SRobert Mustacchi "#include <core_pcbe_table.h>\n"
21053548f91SRobert Mustacchi "\n"
21153548f91SRobert Mustacchi "const struct events_table_t pcbe_core_events_%s[] = {\n";
21253548f91SRobert Mustacchi 
21353548f91SRobert Mustacchi static const char *cpcgen_cfile_table_end = ""
21453548f91SRobert Mustacchi "\t{ NT_END, 0, 0, \"\" }\n"
21553548f91SRobert Mustacchi "};\n";
21653548f91SRobert Mustacchi 
21753548f91SRobert Mustacchi /* BEGIN CSTYLED */
21853548f91SRobert Mustacchi static const char *cpcgen_manual_header = ""
21953548f91SRobert Mustacchi ".\\\" Copyright (c) 2018, Intel Corporation \n"
22053548f91SRobert Mustacchi ".\\\" Copyright (c) 2018, Joyent, Inc.\n"
22153548f91SRobert Mustacchi ".\\\" All rights reserved.\n"
22253548f91SRobert Mustacchi ".\\\"\n"
22353548f91SRobert Mustacchi ".\\\" Redistribution and use in source and binary forms, with or without \n"
22453548f91SRobert Mustacchi ".\\\" modification, are permitted provided that the following conditions are met:\n"
22553548f91SRobert Mustacchi ".\\\"\n"
22653548f91SRobert Mustacchi ".\\\"  1. Redistributions of source code must retain the above copyright notice,\n"
22753548f91SRobert Mustacchi ".\\\"     this list of conditions and the following disclaimer.\n"
22853548f91SRobert Mustacchi ".\\\"\n"
22953548f91SRobert Mustacchi ".\\\"  2. Redistributions in binary form must reproduce the above copyright\n"
23053548f91SRobert Mustacchi ".\\\"     notice, this list of conditions and the following disclaimer in the\n"
23153548f91SRobert Mustacchi ".\\\"     documentation and/or other materials provided with the distribution.\n"
23253548f91SRobert Mustacchi ".\\\"\n"
23353548f91SRobert Mustacchi ".\\\"  3. Neither the name of the Intel Corporation nor the names of its\n"
23453548f91SRobert Mustacchi ".\\\"     contributors may be used to endorse or promote products derived from\n"
23553548f91SRobert Mustacchi ".\\\"     this software without specific prior written permission.\n"
23653548f91SRobert Mustacchi ".\\\"\n"
23753548f91SRobert Mustacchi ".\\\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
23853548f91SRobert Mustacchi ".\\\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
23953548f91SRobert Mustacchi ".\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
24053548f91SRobert Mustacchi ".\\\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
24153548f91SRobert Mustacchi ".\\\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
24253548f91SRobert Mustacchi ".\\\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
24353548f91SRobert Mustacchi ".\\\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
24453548f91SRobert Mustacchi ".\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
24553548f91SRobert Mustacchi ".\\\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
24653548f91SRobert Mustacchi ".\\\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
24753548f91SRobert Mustacchi ".\\\" POSSIBILITY OF SUCH DAMAGE.\n"
24853548f91SRobert Mustacchi ".\\\"\n"
24953548f91SRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n"
25053548f91SRobert Mustacchi ".\\\" data/perfmon%s\n"
25153548f91SRobert Mustacchi ".\\\"\n"
25253548f91SRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n"
25353548f91SRobert Mustacchi ".\\\"\n"
25453548f91SRobert Mustacchi ".\\\" We would like to thank Intel for providing the perfmon data for use in\n"
25553548f91SRobert Mustacchi ".\\\" our manual pages.\n"
25653548f91SRobert Mustacchi ".Dd June 18, 2018\n"
25753548f91SRobert Mustacchi ".Dt %s_EVENTS 3CPC\n"
25853548f91SRobert Mustacchi ".Os\n"
25953548f91SRobert Mustacchi ".Sh NAME\n"
26053548f91SRobert Mustacchi ".Nm %s_events\n"
26153548f91SRobert Mustacchi ".Nd processor model specific performance counter events\n"
26253548f91SRobert Mustacchi ".Sh DESCRIPTION\n"
26353548f91SRobert Mustacchi "This manual page describes events specific to the following Intel CPU\n"
26453548f91SRobert Mustacchi "models and is derived from Intel's perfmon data.\n"
26553548f91SRobert Mustacchi "For more information, please consult the Intel Software Developer's Manual "
26653548f91SRobert Mustacchi "or Intel's perfmon website.\n"
26753548f91SRobert Mustacchi ".Pp\n"
26853548f91SRobert Mustacchi "CPU models described by this document:\n"
26953548f91SRobert Mustacchi ".Bl -bullet\n";
27053548f91SRobert Mustacchi /* END CSTYLED */
27153548f91SRobert Mustacchi 
27253548f91SRobert Mustacchi static const char *cpcgen_manual_data = ""
27353548f91SRobert Mustacchi ".El\n"
27453548f91SRobert Mustacchi ".Pp\n"
27553548f91SRobert Mustacchi "The following events are supported:\n"
27653548f91SRobert Mustacchi ".Bl -tag -width Sy\n";
27753548f91SRobert Mustacchi 
27853548f91SRobert Mustacchi static const char *cpcgen_manual_trailer = ""
27953548f91SRobert Mustacchi ".El\n"
28053548f91SRobert Mustacchi ".Sh SEE ALSO\n"
28153548f91SRobert Mustacchi ".Xr cpc 3CPC\n"
28253548f91SRobert Mustacchi ".Pp\n"
28353548f91SRobert Mustacchi ".Lk https://download.01.org/perfmon/index/";
28453548f91SRobert Mustacchi 
28553548f91SRobert Mustacchi static cpc_map_t *
28653548f91SRobert Mustacchi cpcgen_map_lookup(const char *path)
28753548f91SRobert Mustacchi {
28853548f91SRobert Mustacchi 	cpc_map_t *m;
28953548f91SRobert Mustacchi 
29053548f91SRobert Mustacchi 	for (m = cpcgen_maps; m != NULL; m = m->cmap_next) {
29153548f91SRobert Mustacchi 		if (strcmp(path, m->cmap_path) == 0) {
29253548f91SRobert Mustacchi 			return (m);
29353548f91SRobert Mustacchi 		}
29453548f91SRobert Mustacchi 	}
29553548f91SRobert Mustacchi 
29653548f91SRobert Mustacchi 	return (NULL);
29753548f91SRobert Mustacchi }
29853548f91SRobert Mustacchi 
29953548f91SRobert Mustacchi /*
30053548f91SRobert Mustacchi  * Parse a string of the form 'GenuineIntel-6-2E' and get out the family and
30153548f91SRobert Mustacchi  * model.
30253548f91SRobert Mustacchi  */
30353548f91SRobert Mustacchi static void
304*5fc40de0SRobert Mustacchi cpcgen_parse_model(char *fsr, uint_t *family, uint_t *model, uint_t *nstepp,
305*5fc40de0SRobert Mustacchi     uint_t *steppings)
30653548f91SRobert Mustacchi {
30753548f91SRobert Mustacchi 	const char *bstr = "GenuineIntel";
308*5fc40de0SRobert Mustacchi 	const char *brand, *fam, *mod, *step;
30953548f91SRobert Mustacchi 	char *last;
31053548f91SRobert Mustacchi 	long l;
311*5fc40de0SRobert Mustacchi 	uint_t nstep = 0;
31253548f91SRobert Mustacchi 
313*5fc40de0SRobert Mustacchi 	/*
314*5fc40de0SRobert Mustacchi 	 * Tokeninze the string. There may be an optional stepping portion,
315*5fc40de0SRobert Mustacchi 	 * which has a range of steppings enclosed by '[' and ']' characters.
316*5fc40de0SRobert Mustacchi 	 * While the other parts are required, the stepping may be missing.
317*5fc40de0SRobert Mustacchi 	 */
31853548f91SRobert Mustacchi 	if ((brand = strtok_r(fsr, "-", &last)) == NULL ||
31953548f91SRobert Mustacchi 	    (fam = strtok_r(NULL, "-", &last)) == NULL ||
32053548f91SRobert Mustacchi 	    (mod = strtok_r(NULL, "-", &last)) == NULL) {
32153548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse processor id \"%s\"", fsr);
32253548f91SRobert Mustacchi 	}
323*5fc40de0SRobert Mustacchi 	step = strtok_r(NULL, "-", &last);
32453548f91SRobert Mustacchi 
32553548f91SRobert Mustacchi 	if (strcmp(bstr, brand) != 0) {
32653548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "brand string \"%s\" did not match \"%s\"",
32753548f91SRobert Mustacchi 		    brand, bstr);
32853548f91SRobert Mustacchi 	}
32953548f91SRobert Mustacchi 
33053548f91SRobert Mustacchi 	errno = 0;
33153548f91SRobert Mustacchi 	l = strtol(fam, &last, 16);
332*5fc40de0SRobert Mustacchi 	if (errno != 0 || l < 0 || l > UINT_MAX || *last != '\0') {
33353548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse family \"%s\"", fam);
33453548f91SRobert Mustacchi 	}
33553548f91SRobert Mustacchi 	*family = (uint_t)l;
33653548f91SRobert Mustacchi 
33753548f91SRobert Mustacchi 	l = strtol(mod, &last, 16);
338*5fc40de0SRobert Mustacchi 	if (errno != 0 || l < 0 || l > UINT_MAX || *last != '\0') {
33953548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse model \"%s\"", mod);
34053548f91SRobert Mustacchi 	}
34153548f91SRobert Mustacchi 	*model = (uint_t)l;
342*5fc40de0SRobert Mustacchi 
343*5fc40de0SRobert Mustacchi 	if (step == NULL) {
344*5fc40de0SRobert Mustacchi 		*nstepp = 0;
345*5fc40de0SRobert Mustacchi 		return;
346*5fc40de0SRobert Mustacchi 	}
347*5fc40de0SRobert Mustacchi 
348*5fc40de0SRobert Mustacchi 	if (*step != '[' || ((last = strrchr(step, ']')) == NULL)) {
349*5fc40de0SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse stepping \"%s\": missing "
350*5fc40de0SRobert Mustacchi 		    "stepping range brackets", step);
351*5fc40de0SRobert Mustacchi 	}
352*5fc40de0SRobert Mustacchi 	step++;
353*5fc40de0SRobert Mustacchi 	*last = '\0';
354*5fc40de0SRobert Mustacchi 	while (*step != '\0') {
355*5fc40de0SRobert Mustacchi 		if (!isxdigit(*step)) {
356*5fc40de0SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse stepping: invalid "
357*5fc40de0SRobert Mustacchi 			    "stepping identifier '0x%x'", *step);
358*5fc40de0SRobert Mustacchi 		}
359*5fc40de0SRobert Mustacchi 
360*5fc40de0SRobert Mustacchi 		if (nstep >= CPROC_MAX_STEPPINGS) {
361*5fc40de0SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse stepping: "
362*5fc40de0SRobert Mustacchi 			    "encountered too many steppings");
363*5fc40de0SRobert Mustacchi 		}
364*5fc40de0SRobert Mustacchi 
365*5fc40de0SRobert Mustacchi 		switch (*step) {
366*5fc40de0SRobert Mustacchi 		case '0':
367*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0x0;
368*5fc40de0SRobert Mustacchi 			break;
369*5fc40de0SRobert Mustacchi 		case '1':
370*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0x1;
371*5fc40de0SRobert Mustacchi 			break;
372*5fc40de0SRobert Mustacchi 		case '2':
373*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0x2;
374*5fc40de0SRobert Mustacchi 			break;
375*5fc40de0SRobert Mustacchi 		case '3':
376*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0x3;
377*5fc40de0SRobert Mustacchi 			break;
378*5fc40de0SRobert Mustacchi 		case '4':
379*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0x4;
380*5fc40de0SRobert Mustacchi 			break;
381*5fc40de0SRobert Mustacchi 		case '5':
382*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0x5;
383*5fc40de0SRobert Mustacchi 			break;
384*5fc40de0SRobert Mustacchi 		case '6':
385*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0x6;
386*5fc40de0SRobert Mustacchi 			break;
387*5fc40de0SRobert Mustacchi 		case '7':
388*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0x7;
389*5fc40de0SRobert Mustacchi 			break;
390*5fc40de0SRobert Mustacchi 		case '8':
391*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0x8;
392*5fc40de0SRobert Mustacchi 			break;
393*5fc40de0SRobert Mustacchi 		case '9':
394*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0x9;
395*5fc40de0SRobert Mustacchi 			break;
396*5fc40de0SRobert Mustacchi 		case 'a':
397*5fc40de0SRobert Mustacchi 		case 'A':
398*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0xa;
399*5fc40de0SRobert Mustacchi 			break;
400*5fc40de0SRobert Mustacchi 		case 'b':
401*5fc40de0SRobert Mustacchi 		case 'B':
402*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0xb;
403*5fc40de0SRobert Mustacchi 			break;
404*5fc40de0SRobert Mustacchi 		case 'c':
405*5fc40de0SRobert Mustacchi 		case 'C':
406*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0xc;
407*5fc40de0SRobert Mustacchi 			break;
408*5fc40de0SRobert Mustacchi 		case 'd':
409*5fc40de0SRobert Mustacchi 		case 'D':
410*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0xd;
411*5fc40de0SRobert Mustacchi 			break;
412*5fc40de0SRobert Mustacchi 		case 'e':
413*5fc40de0SRobert Mustacchi 		case 'E':
414*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0xe;
415*5fc40de0SRobert Mustacchi 			break;
416*5fc40de0SRobert Mustacchi 		case 'f':
417*5fc40de0SRobert Mustacchi 		case 'F':
418*5fc40de0SRobert Mustacchi 			steppings[nstep] = 0xf;
419*5fc40de0SRobert Mustacchi 			break;
420*5fc40de0SRobert Mustacchi 		default:
421*5fc40de0SRobert Mustacchi 			errx(EXIT_FAILURE, "encountered non-hex stepping "
422*5fc40de0SRobert Mustacchi 			    "character: '%c'", *step);
423*5fc40de0SRobert Mustacchi 		}
424*5fc40de0SRobert Mustacchi 		nstep++;
425*5fc40de0SRobert Mustacchi 		step++;
426*5fc40de0SRobert Mustacchi 	}
427*5fc40de0SRobert Mustacchi 
428*5fc40de0SRobert Mustacchi 	*nstepp = nstep;
42953548f91SRobert Mustacchi }
43053548f91SRobert Mustacchi 
43153548f91SRobert Mustacchi static nvlist_t *
43253548f91SRobert Mustacchi cpcgen_read_datafile(const char *datadir, const char *file)
43353548f91SRobert Mustacchi {
43453548f91SRobert Mustacchi 	int fd;
43553548f91SRobert Mustacchi 	char *path;
43653548f91SRobert Mustacchi 	struct stat st;
43753548f91SRobert Mustacchi 	void *map;
43853548f91SRobert Mustacchi 	nvlist_t *nvl;
43953548f91SRobert Mustacchi 	nvlist_parse_json_error_t jerr;
44053548f91SRobert Mustacchi 
44153548f91SRobert Mustacchi 	if (asprintf(&path, "%s/%s", datadir, file) == -1) {
44253548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to data file %s",
44353548f91SRobert Mustacchi 		    file);
44453548f91SRobert Mustacchi 	}
44553548f91SRobert Mustacchi 
44653548f91SRobert Mustacchi 	if ((fd = open(path, O_RDONLY)) < 0) {
44753548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data file %s", path);
44853548f91SRobert Mustacchi 	}
44953548f91SRobert Mustacchi 
45053548f91SRobert Mustacchi 	if (fstat(fd, &st) != 0) {
45153548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to stat %s", path);
45253548f91SRobert Mustacchi 	}
45353548f91SRobert Mustacchi 
45453548f91SRobert Mustacchi 	if ((map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
45553548f91SRobert Mustacchi 	    fd, 0)) == MAP_FAILED) {
45653548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to mmap %s", path);
45753548f91SRobert Mustacchi 	}
45853548f91SRobert Mustacchi 
45953548f91SRobert Mustacchi 	if (nvlist_parse_json(map, st.st_size, &nvl, NVJSON_FORCE_INTEGER,
46053548f91SRobert Mustacchi 	    &jerr) != 0) {
46153548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse file %s at pos %ld: %s",
46253548f91SRobert Mustacchi 		    path, jerr.nje_pos, jerr.nje_message);
46353548f91SRobert Mustacchi 	}
46453548f91SRobert Mustacchi 
46553548f91SRobert Mustacchi 	if (munmap(map, st.st_size) != 0) {
46653548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to munmap %s", path);
46753548f91SRobert Mustacchi 	}
46853548f91SRobert Mustacchi 
46953548f91SRobert Mustacchi 	if (close(fd) != 0) {
47053548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to close data file %s", path);
47153548f91SRobert Mustacchi 	}
47253548f91SRobert Mustacchi 	free(path);
47353548f91SRobert Mustacchi 
47453548f91SRobert Mustacchi 	return (nvl);
47553548f91SRobert Mustacchi }
47653548f91SRobert Mustacchi 
47753548f91SRobert Mustacchi /*
47853548f91SRobert Mustacchi  * Check the whitelist to see if we should use this model.
47953548f91SRobert Mustacchi  */
48053548f91SRobert Mustacchi static const char *
48153548f91SRobert Mustacchi cpcgen_use_arch(const char *path, cpc_type_t type, const char *platform)
48253548f91SRobert Mustacchi {
48353548f91SRobert Mustacchi 	const char *slash;
48453548f91SRobert Mustacchi 	size_t len;
48553548f91SRobert Mustacchi 	uint_t i;
48653548f91SRobert Mustacchi 
48753548f91SRobert Mustacchi 	if (*path != '/') {
48853548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
48953548f91SRobert Mustacchi 		    "leading '/'", path);
49053548f91SRobert Mustacchi 	}
49153548f91SRobert Mustacchi 	if ((slash = strchr(path + 1, '/')) == NULL) {
49253548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
49353548f91SRobert Mustacchi 		    "second '/'", path);
49453548f91SRobert Mustacchi 	}
49553548f91SRobert Mustacchi 	/* Account for the last '/' character. */
49653548f91SRobert Mustacchi 	len = slash - path - 1;
49753548f91SRobert Mustacchi 	assert(len > 0);
49853548f91SRobert Mustacchi 
49953548f91SRobert Mustacchi 	for (i = 0; cpcgen_whitelist[i].cwhite_short != NULL; i++) {
50053548f91SRobert Mustacchi 		if (platform != NULL && strcasecmp(platform,
50153548f91SRobert Mustacchi 		    cpcgen_whitelist[i].cwhite_short) != 0)
50253548f91SRobert Mustacchi 			continue;
50353548f91SRobert Mustacchi 		if (strncmp(path + 1, cpcgen_whitelist[i].cwhite_short,
50453548f91SRobert Mustacchi 		    len) == 0 &&
50553548f91SRobert Mustacchi 		    (cpcgen_whitelist[i].cwhite_mask & type) == type) {
50653548f91SRobert Mustacchi 			return (cpcgen_whitelist[i].cwhite_human);
50753548f91SRobert Mustacchi 		}
50853548f91SRobert Mustacchi 	}
50953548f91SRobert Mustacchi 
51053548f91SRobert Mustacchi 	return (NULL);
51153548f91SRobert Mustacchi }
51253548f91SRobert Mustacchi 
51353548f91SRobert Mustacchi /*
51453548f91SRobert Mustacchi  * Read in the mapfile.csv that is used to map between processor families and
51553548f91SRobert Mustacchi  * parse this. Each line has a comma separated value.
51653548f91SRobert Mustacchi  */
51753548f91SRobert Mustacchi static void
51853548f91SRobert Mustacchi cpcgen_read_mapfile(const char *datadir, const char *platform)
51953548f91SRobert Mustacchi {
52053548f91SRobert Mustacchi 	FILE *map;
52153548f91SRobert Mustacchi 	char *mappath, *last;
52253548f91SRobert Mustacchi 	char *data = NULL;
52353548f91SRobert Mustacchi 	size_t datalen = 0;
52453548f91SRobert Mustacchi 	uint_t lineno;
52553548f91SRobert Mustacchi 
52653548f91SRobert Mustacchi 	if (asprintf(&mappath, "%s/%s", datadir, cpcgen_mapfile) == -1) {
52753548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to mapfile");
52853548f91SRobert Mustacchi 	}
52953548f91SRobert Mustacchi 
53053548f91SRobert Mustacchi 	if ((map = fopen(mappath, "r")) == NULL) {
53153548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data mapfile %s", mappath);
53253548f91SRobert Mustacchi 	}
53353548f91SRobert Mustacchi 
53453548f91SRobert Mustacchi 	lineno = 0;
53553548f91SRobert Mustacchi 	while (getline(&data, &datalen, map) != -1) {
53653548f91SRobert Mustacchi 		char *fstr, *path, *tstr;
53753548f91SRobert Mustacchi 		const char *name;
538*5fc40de0SRobert Mustacchi 		uint_t family, model, nsteps;
539*5fc40de0SRobert Mustacchi 		uint_t steppings[CPROC_MAX_STEPPINGS];
540*5fc40de0SRobert Mustacchi 
54153548f91SRobert Mustacchi 		cpc_type_t type;
54253548f91SRobert Mustacchi 		cpc_map_t *map;
54353548f91SRobert Mustacchi 		cpc_proc_t *proc;
54453548f91SRobert Mustacchi 
54553548f91SRobert Mustacchi 		/*
54653548f91SRobert Mustacchi 		 * The first line contains the header:
54753548f91SRobert Mustacchi 		 * Family-model,Version,Filename,EventType
54853548f91SRobert Mustacchi 		 */
54953548f91SRobert Mustacchi 		lineno++;
55053548f91SRobert Mustacchi 		if (lineno == 1) {
55153548f91SRobert Mustacchi 			continue;
55253548f91SRobert Mustacchi 		}
55353548f91SRobert Mustacchi 
55453548f91SRobert Mustacchi 		if ((fstr = strtok_r(data, ",", &last)) == NULL ||
55553548f91SRobert Mustacchi 		    strtok_r(NULL, ",", &last) == NULL ||
55653548f91SRobert Mustacchi 		    (path = strtok_r(NULL, ",", &last)) == NULL ||
55753548f91SRobert Mustacchi 		    (tstr = strtok_r(NULL, "\n", &last)) == NULL) {
55853548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse mapfile line "
55953548f91SRobert Mustacchi 			    "%u in %s", lineno, mappath);
56053548f91SRobert Mustacchi 		}
56153548f91SRobert Mustacchi 
562*5fc40de0SRobert Mustacchi 		cpcgen_parse_model(fstr, &family, &model, &nsteps, steppings);
56353548f91SRobert Mustacchi 
56453548f91SRobert Mustacchi 		if (strcmp(tstr, "core") == 0) {
56553548f91SRobert Mustacchi 			type = CPC_FILE_CORE;
56653548f91SRobert Mustacchi 		} else if (strcmp(tstr, "offcore") == 0) {
56753548f91SRobert Mustacchi 			type = CPC_FILE_OFF_CORE;
56853548f91SRobert Mustacchi 		} else if (strcmp(tstr, "uncore") == 0) {
56953548f91SRobert Mustacchi 			type = CPC_FILE_UNCORE;
57053548f91SRobert Mustacchi 		} else if (strcmp(tstr, "fp_arith_inst") == 0) {
57153548f91SRobert Mustacchi 			type = CPC_FILE_FP_MATH;
57253548f91SRobert Mustacchi 		} else if (strcmp(tstr, "uncore experimental") == 0) {
57353548f91SRobert Mustacchi 			type = CPC_FILE_UNCORE_EXP;
57453548f91SRobert Mustacchi 		} else {
57553548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "unknown file type \"%s\" on line "
57653548f91SRobert Mustacchi 			    "%u", tstr, lineno);
57753548f91SRobert Mustacchi 		}
57853548f91SRobert Mustacchi 
57953548f91SRobert Mustacchi 		if ((name = cpcgen_use_arch(path, type, platform)) == NULL)
58053548f91SRobert Mustacchi 			continue;
58153548f91SRobert Mustacchi 
58253548f91SRobert Mustacchi 		if ((map = cpcgen_map_lookup(path)) == NULL) {
58353548f91SRobert Mustacchi 			nvlist_t *parsed;
58453548f91SRobert Mustacchi 
58553548f91SRobert Mustacchi 			parsed = cpcgen_read_datafile(datadir, path);
58653548f91SRobert Mustacchi 
58753548f91SRobert Mustacchi 			if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) {
58853548f91SRobert Mustacchi 				err(EXIT_FAILURE, "failed to allocate space "
58953548f91SRobert Mustacchi 				    "for cpc file");
59053548f91SRobert Mustacchi 			}
59153548f91SRobert Mustacchi 
59253548f91SRobert Mustacchi 			if ((map->cmap_path = strdup(path)) == NULL) {
59353548f91SRobert Mustacchi 				err(EXIT_FAILURE, "failed to duplicate path "
59453548f91SRobert Mustacchi 				    "string");
59553548f91SRobert Mustacchi 			}
59653548f91SRobert Mustacchi 
59753548f91SRobert Mustacchi 			map->cmap_type = type;
59853548f91SRobert Mustacchi 			map->cmap_data = parsed;
59953548f91SRobert Mustacchi 			map->cmap_next = cpcgen_maps;
60053548f91SRobert Mustacchi 			map->cmap_name = name;
601*5fc40de0SRobert Mustacchi 			map->cmap_procs = NULL;
60253548f91SRobert Mustacchi 			cpcgen_maps = map;
60353548f91SRobert Mustacchi 		}
60453548f91SRobert Mustacchi 
605*5fc40de0SRobert Mustacchi 		if ((proc = calloc(1, sizeof (cpc_proc_t))) == NULL) {
60653548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
60753548f91SRobert Mustacchi 			    "family and model tracking");
60853548f91SRobert Mustacchi 		}
60953548f91SRobert Mustacchi 
61053548f91SRobert Mustacchi 		proc->cproc_family = family;
61153548f91SRobert Mustacchi 		proc->cproc_model = model;
612*5fc40de0SRobert Mustacchi 		proc->cproc_nsteps = nsteps;
613*5fc40de0SRobert Mustacchi 		if (nsteps > 0) {
614*5fc40de0SRobert Mustacchi 			bcopy(steppings, proc->cproc_steppings,
615*5fc40de0SRobert Mustacchi 			    sizeof (steppings));
616*5fc40de0SRobert Mustacchi 		}
61753548f91SRobert Mustacchi 		proc->cproc_next = map->cmap_procs;
61853548f91SRobert Mustacchi 		map->cmap_procs = proc;
61953548f91SRobert Mustacchi 	}
62053548f91SRobert Mustacchi 
62153548f91SRobert Mustacchi 	if (errno != 0 || ferror(map)) {
62253548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to read %s", mappath);
62353548f91SRobert Mustacchi 	}
62453548f91SRobert Mustacchi 
62553548f91SRobert Mustacchi 	if (fclose(map) == EOF) {
62653548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to close %s", mappath);
62753548f91SRobert Mustacchi 	}
62853548f91SRobert Mustacchi 	free(data);
62953548f91SRobert Mustacchi 	free(mappath);
63053548f91SRobert Mustacchi }
63153548f91SRobert Mustacchi 
63253548f91SRobert Mustacchi static char *
63353548f91SRobert Mustacchi cpcgen_manual_name(cpc_map_t *map)
63453548f91SRobert Mustacchi {
63553548f91SRobert Mustacchi 	char *name;
63653548f91SRobert Mustacchi 
63753548f91SRobert Mustacchi 	if (asprintf(&name, "%s_events.3cpc", map->cmap_name) == -1) {
63853548f91SRobert Mustacchi 		warn("failed to assemble manual page name for %s",
63953548f91SRobert Mustacchi 		    map->cmap_path);
64053548f91SRobert Mustacchi 		return (NULL);
64153548f91SRobert Mustacchi 	}
64253548f91SRobert Mustacchi 
64353548f91SRobert Mustacchi 	return (name);
64453548f91SRobert Mustacchi }
64553548f91SRobert Mustacchi 
64653548f91SRobert Mustacchi static boolean_t
64753548f91SRobert Mustacchi cpcgen_manual_file_before(FILE *f, cpc_map_t *map)
64853548f91SRobert Mustacchi {
64953548f91SRobert Mustacchi 	size_t i;
65053548f91SRobert Mustacchi 	char *upper;
65153548f91SRobert Mustacchi 	cpc_proc_t *proc;
65253548f91SRobert Mustacchi 
65353548f91SRobert Mustacchi 	if ((upper = strdup(map->cmap_name)) == NULL) {
65453548f91SRobert Mustacchi 		warn("failed to duplicate manual name for %s", map->cmap_name);
65553548f91SRobert Mustacchi 		return (B_FALSE);
65653548f91SRobert Mustacchi 	}
65753548f91SRobert Mustacchi 
65853548f91SRobert Mustacchi 	for (i = 0; upper[i] != '\0'; i++) {
65953548f91SRobert Mustacchi 		upper[i] = toupper(upper[i]);
66053548f91SRobert Mustacchi 	}
66153548f91SRobert Mustacchi 
66253548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_header, map->cmap_path, upper,
66353548f91SRobert Mustacchi 	    map->cmap_name) == -1) {
66453548f91SRobert Mustacchi 		warn("failed to write out manual header for %s",
66553548f91SRobert Mustacchi 		    map->cmap_name);
66653548f91SRobert Mustacchi 		free(upper);
66753548f91SRobert Mustacchi 		return (B_FALSE);
66853548f91SRobert Mustacchi 	}
66953548f91SRobert Mustacchi 
67053548f91SRobert Mustacchi 	for (proc = map->cmap_procs; proc != NULL; proc = proc->cproc_next) {
671*5fc40de0SRobert Mustacchi 		if (proc->cproc_nsteps > 0) {
672*5fc40de0SRobert Mustacchi 			uint_t step;
673*5fc40de0SRobert Mustacchi 
674*5fc40de0SRobert Mustacchi 			for (step = 0; step < proc->cproc_nsteps; step++) {
675*5fc40de0SRobert Mustacchi 				if (fprintf(f, ".It\n.Sy Family 0x%x, Model "
676*5fc40de0SRobert Mustacchi 				    "0x%x, Stepping 0x%x\n",
677*5fc40de0SRobert Mustacchi 				    proc->cproc_family, proc->cproc_model,
678*5fc40de0SRobert Mustacchi 				    proc->cproc_steppings[step]) == -1) {
679*5fc40de0SRobert Mustacchi 					warn("failed to write out model "
680*5fc40de0SRobert Mustacchi 					    "information for %s",
68153548f91SRobert Mustacchi 					    map->cmap_name);
68253548f91SRobert Mustacchi 					free(upper);
68353548f91SRobert Mustacchi 					return (B_FALSE);
68453548f91SRobert Mustacchi 				}
68553548f91SRobert Mustacchi 			}
686*5fc40de0SRobert Mustacchi 		} else {
687*5fc40de0SRobert Mustacchi 			if (fprintf(f, ".It\n.Sy Family 0x%x, Model 0x%x\n",
688*5fc40de0SRobert Mustacchi 			    proc->cproc_family, proc->cproc_model) == -1) {
689*5fc40de0SRobert Mustacchi 				warn("failed to write out model information "
690*5fc40de0SRobert Mustacchi 				    "for %s", map->cmap_name);
691*5fc40de0SRobert Mustacchi 				free(upper);
692*5fc40de0SRobert Mustacchi 				return (B_FALSE);
693*5fc40de0SRobert Mustacchi 			}
694*5fc40de0SRobert Mustacchi 		}
695*5fc40de0SRobert Mustacchi 	}
69653548f91SRobert Mustacchi 
69753548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_data, map->cmap_path, upper,
69853548f91SRobert Mustacchi 	    map->cmap_name) == -1) {
69953548f91SRobert Mustacchi 		warn("failed to write out manual header for %s",
70053548f91SRobert Mustacchi 		    map->cmap_name);
70153548f91SRobert Mustacchi 		free(upper);
70253548f91SRobert Mustacchi 		return (B_FALSE);
70353548f91SRobert Mustacchi 	}
70453548f91SRobert Mustacchi 
70553548f91SRobert Mustacchi 	free(upper);
70653548f91SRobert Mustacchi 	return (B_TRUE);
70753548f91SRobert Mustacchi }
70853548f91SRobert Mustacchi 
70953548f91SRobert Mustacchi static boolean_t
71053548f91SRobert Mustacchi cpcgen_manual_file_after(FILE *f, cpc_map_t *map)
71153548f91SRobert Mustacchi {
71253548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_trailer) == -1) {
71353548f91SRobert Mustacchi 		warn("failed to write out manual header for %s",
71453548f91SRobert Mustacchi 		    map->cmap_name);
71553548f91SRobert Mustacchi 		return (B_FALSE);
71653548f91SRobert Mustacchi 	}
71753548f91SRobert Mustacchi 
71853548f91SRobert Mustacchi 	return (B_TRUE);
71953548f91SRobert Mustacchi }
72053548f91SRobert Mustacchi 
72153548f91SRobert Mustacchi static boolean_t
72253548f91SRobert Mustacchi cpcgen_manual_event(FILE *f, nvlist_t *nvl, const char *path, uint32_t ent)
72353548f91SRobert Mustacchi {
72453548f91SRobert Mustacchi 	char *event, *lname, *brief = NULL, *public = NULL, *errata = NULL;
72553548f91SRobert Mustacchi 	size_t i;
72653548f91SRobert Mustacchi 
72753548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
72853548f91SRobert Mustacchi 		warnx("Found event without 'EventName' property "
72953548f91SRobert Mustacchi 		    "in %s, entry %u", path, ent);
73053548f91SRobert Mustacchi 		return (B_FALSE);
73153548f91SRobert Mustacchi 	}
73253548f91SRobert Mustacchi 
73353548f91SRobert Mustacchi 	/*
73453548f91SRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
73553548f91SRobert Mustacchi 	 */
73653548f91SRobert Mustacchi 	if ((lname = strdup(event)) == NULL) {
73753548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", event);
73853548f91SRobert Mustacchi 	}
73953548f91SRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
74053548f91SRobert Mustacchi 		lname[i] = tolower(event[i]);
74153548f91SRobert Mustacchi 	}
74253548f91SRobert Mustacchi 
74353548f91SRobert Mustacchi 	/*
74453548f91SRobert Mustacchi 	 * Try to get the other event fields, but if they're not there, don't
74553548f91SRobert Mustacchi 	 * worry about it.
74653548f91SRobert Mustacchi 	 */
74753548f91SRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "BriefDescription", &brief);
74853548f91SRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "PublicDescription", &public);
74953548f91SRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "Errata", &errata);
75053548f91SRobert Mustacchi 	if (errata != NULL && (strcmp(errata, "0") == 0 ||
75153548f91SRobert Mustacchi 	    strcmp(errata, "null") == 0)) {
75253548f91SRobert Mustacchi 		errata = NULL;
75353548f91SRobert Mustacchi 	}
75453548f91SRobert Mustacchi 
75553548f91SRobert Mustacchi 	if (fprintf(f, ".It Sy %s\n", lname) == -1) {
75653548f91SRobert Mustacchi 		warn("failed to write out probe entry %s", event);
75753548f91SRobert Mustacchi 		free(lname);
75853548f91SRobert Mustacchi 		return (B_FALSE);
75953548f91SRobert Mustacchi 	}
76053548f91SRobert Mustacchi 
76153548f91SRobert Mustacchi 	if (public != NULL) {
76253548f91SRobert Mustacchi 		if (fprintf(f, "%s\n", public) == -1) {
76353548f91SRobert Mustacchi 			warn("failed to write out probe entry %s", event);
76453548f91SRobert Mustacchi 			free(lname);
76553548f91SRobert Mustacchi 			return (B_FALSE);
76653548f91SRobert Mustacchi 		}
76753548f91SRobert Mustacchi 	} else if (brief != NULL) {
76853548f91SRobert Mustacchi 		if (fprintf(f, "%s\n", brief) == -1) {
76953548f91SRobert Mustacchi 			warn("failed to write out probe entry %s", event);
77053548f91SRobert Mustacchi 			free(lname);
77153548f91SRobert Mustacchi 			return (B_FALSE);
77253548f91SRobert Mustacchi 		}
77353548f91SRobert Mustacchi 	}
77453548f91SRobert Mustacchi 
77553548f91SRobert Mustacchi 	if (errata != NULL) {
77653548f91SRobert Mustacchi 		if (fprintf(f, ".Pp\nThe following errata may apply to this: "
77753548f91SRobert Mustacchi 		    "%s\n", errata) == -1) {
77853548f91SRobert Mustacchi 
77953548f91SRobert Mustacchi 			warn("failed to write out probe entry %s", event);
78053548f91SRobert Mustacchi 			free(lname);
78153548f91SRobert Mustacchi 			return (B_FALSE);
78253548f91SRobert Mustacchi 		}
78353548f91SRobert Mustacchi 	}
78453548f91SRobert Mustacchi 
78553548f91SRobert Mustacchi 	free(lname);
78653548f91SRobert Mustacchi 	return (B_TRUE);
78753548f91SRobert Mustacchi }
78853548f91SRobert Mustacchi 
78953548f91SRobert Mustacchi static char *
79053548f91SRobert Mustacchi cpcgen_cfile_name(cpc_map_t *map)
79153548f91SRobert Mustacchi {
79253548f91SRobert Mustacchi 	char *name;
79353548f91SRobert Mustacchi 
79453548f91SRobert Mustacchi 	if (asprintf(&name, "core_pcbe_%s.c", map->cmap_name) == -1) {
79553548f91SRobert Mustacchi 		warn("failed to assemble file name for %s", map->cmap_path);
79653548f91SRobert Mustacchi 		return (NULL);
79753548f91SRobert Mustacchi 	}
79853548f91SRobert Mustacchi 
79953548f91SRobert Mustacchi 	return (name);
80053548f91SRobert Mustacchi }
80153548f91SRobert Mustacchi 
80253548f91SRobert Mustacchi static boolean_t
80353548f91SRobert Mustacchi cpcgen_cfile_file_before(FILE *f, cpc_map_t *map)
80453548f91SRobert Mustacchi {
80553548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, map->cmap_path) == -1) {
80653548f91SRobert Mustacchi 		warn("failed to write header to temporary file for %s",
80753548f91SRobert Mustacchi 		    map->cmap_path);
80853548f91SRobert Mustacchi 		return (B_FALSE);
80953548f91SRobert Mustacchi 	}
81053548f91SRobert Mustacchi 
81153548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_table_start, map->cmap_name) == -1) {
81253548f91SRobert Mustacchi 		warn("failed to write header to temporary file for %s",
81353548f91SRobert Mustacchi 		    map->cmap_path);
81453548f91SRobert Mustacchi 		return (B_FALSE);
81553548f91SRobert Mustacchi 	}
81653548f91SRobert Mustacchi 
81753548f91SRobert Mustacchi 	return (B_TRUE);
81853548f91SRobert Mustacchi }
81953548f91SRobert Mustacchi 
82053548f91SRobert Mustacchi static boolean_t
82153548f91SRobert Mustacchi cpcgen_cfile_file_after(FILE *f, cpc_map_t *map)
82253548f91SRobert Mustacchi {
82353548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_table_end) == -1) {
82453548f91SRobert Mustacchi 		warn("failed to write footer to temporary file for %s",
82553548f91SRobert Mustacchi 		    map->cmap_path);
82653548f91SRobert Mustacchi 		return (B_FALSE);
82753548f91SRobert Mustacchi 	}
82853548f91SRobert Mustacchi 
82953548f91SRobert Mustacchi 	return (B_TRUE);
83053548f91SRobert Mustacchi }
83153548f91SRobert Mustacchi 
83253548f91SRobert Mustacchi static boolean_t
83353548f91SRobert Mustacchi cpcgen_cfile_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent)
83453548f91SRobert Mustacchi {
83553548f91SRobert Mustacchi 	char *ecode, *umask, *name, *counter, *lname, *cmask;
83653548f91SRobert Mustacchi 	size_t i;
83753548f91SRobert Mustacchi 
83853548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &name) != 0) {
83953548f91SRobert Mustacchi 		warnx("Found event without 'EventName' property "
84053548f91SRobert Mustacchi 		    "in %s, entry %u", path, ent);
84153548f91SRobert Mustacchi 		return (B_FALSE);
84253548f91SRobert Mustacchi 	}
84353548f91SRobert Mustacchi 
84453548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
84553548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
84653548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0) {
84753548f91SRobert Mustacchi 		warnx("event %s (index %u) from %s, missing "
84853548f91SRobert Mustacchi 		    "required properties for C file translation",
84953548f91SRobert Mustacchi 		    name, ent, path);
85053548f91SRobert Mustacchi 		return (B_FALSE);
85153548f91SRobert Mustacchi 	}
85253548f91SRobert Mustacchi 
85353548f91SRobert Mustacchi 	/*
85453548f91SRobert Mustacchi 	 * While we could try and parse the counters manually, just do this the
85553548f91SRobert Mustacchi 	 * max power way for now based on all possible values.
85653548f91SRobert Mustacchi 	 */
85753548f91SRobert Mustacchi 	if (strcmp(counter, "0") == 0 || strcmp(counter, "0,") == 0) {
85853548f91SRobert Mustacchi 		cmask = "C0";
85953548f91SRobert Mustacchi 	} else if (strcmp(counter, "1") == 0) {
86053548f91SRobert Mustacchi 		cmask = "C1";
86153548f91SRobert Mustacchi 	} else if (strcmp(counter, "2") == 0) {
86253548f91SRobert Mustacchi 		cmask = "C2";
86353548f91SRobert Mustacchi 	} else if (strcmp(counter, "3") == 0) {
86453548f91SRobert Mustacchi 		cmask = "C3";
86553548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,1") == 0) {
86653548f91SRobert Mustacchi 		cmask = "C0|C1";
86753548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,1,2") == 0) {
86853548f91SRobert Mustacchi 		cmask = "C0|C1|C2";
86953548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,1,2,3") == 0) {
87053548f91SRobert Mustacchi 		cmask = "C0|C1|C2|C3";
87153548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,2,3") == 0) {
87253548f91SRobert Mustacchi 		cmask = "C0|C2|C3";
87353548f91SRobert Mustacchi 	} else if (strcmp(counter, "1,2,3") == 0) {
87453548f91SRobert Mustacchi 		cmask = "C1|C2|C3";
87553548f91SRobert Mustacchi 	} else if (strcmp(counter, "2,3") == 0) {
87653548f91SRobert Mustacchi 		cmask = "C2|C3";
87753548f91SRobert Mustacchi 	} else {
87853548f91SRobert Mustacchi 		warnx("event %s (index %u) from %s, has unknown "
87953548f91SRobert Mustacchi 		    "counter value \"%s\"", name, ent, path, counter);
88053548f91SRobert Mustacchi 		return (B_FALSE);
88153548f91SRobert Mustacchi 	}
88253548f91SRobert Mustacchi 
88353548f91SRobert Mustacchi 
88453548f91SRobert Mustacchi 	/*
88553548f91SRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
88653548f91SRobert Mustacchi 	 */
88753548f91SRobert Mustacchi 	if ((lname = strdup(name)) == NULL) {
88853548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", name);
88953548f91SRobert Mustacchi 	}
89053548f91SRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
89153548f91SRobert Mustacchi 		lname[i] = tolower(name[i]);
89253548f91SRobert Mustacchi 	}
89353548f91SRobert Mustacchi 
89453548f91SRobert Mustacchi 	if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, cmask,
89553548f91SRobert Mustacchi 	    lname) == -1) {
89653548f91SRobert Mustacchi 		warn("failed to write out entry %s from %s", name, path);
89753548f91SRobert Mustacchi 		free(lname);
89853548f91SRobert Mustacchi 		return (B_FALSE);
89953548f91SRobert Mustacchi 	}
90053548f91SRobert Mustacchi 
90153548f91SRobert Mustacchi 	free(lname);
90253548f91SRobert Mustacchi 
90353548f91SRobert Mustacchi 	/*
90453548f91SRobert Mustacchi 	 * Check if we have any PAPI aliases.
90553548f91SRobert Mustacchi 	 */
90653548f91SRobert Mustacchi 	for (i = 0; cpcgen_papi_map[i].cpapi_intc != NULL; i++) {
90753548f91SRobert Mustacchi 		if (strcmp(name, cpcgen_papi_map[i].cpapi_intc) != 0)
90853548f91SRobert Mustacchi 			continue;
90953548f91SRobert Mustacchi 
91053548f91SRobert Mustacchi 		if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask,
91153548f91SRobert Mustacchi 		    cmask, cpcgen_papi_map[i].cpapi_papi) == -1) {
91253548f91SRobert Mustacchi 			warn("failed to write out entry %s from %s", name,
91353548f91SRobert Mustacchi 			    path);
91453548f91SRobert Mustacchi 			return (B_FALSE);
91553548f91SRobert Mustacchi 		}
91653548f91SRobert Mustacchi 	}
91753548f91SRobert Mustacchi 
91853548f91SRobert Mustacchi 	return (B_TRUE);
91953548f91SRobert Mustacchi }
92053548f91SRobert Mustacchi 
921*5fc40de0SRobert Mustacchi static boolean_t
922*5fc40de0SRobert Mustacchi cpcgen_generate_map(FILE *f, cpc_map_t *map, boolean_t start)
923*5fc40de0SRobert Mustacchi {
924*5fc40de0SRobert Mustacchi 	cpc_proc_t *p;
925*5fc40de0SRobert Mustacchi 
926*5fc40de0SRobert Mustacchi 	if (fprintf(f, "\t%sif (", start ? "" : "} else ") == -1) {
927*5fc40de0SRobert Mustacchi 		return (B_FALSE);
928*5fc40de0SRobert Mustacchi 	}
929*5fc40de0SRobert Mustacchi 
930*5fc40de0SRobert Mustacchi 	for (p = map->cmap_procs; p != NULL; p = p->cproc_next) {
931*5fc40de0SRobert Mustacchi 		/*
932*5fc40de0SRobert Mustacchi 		 * Make sure the line is padded so the generated C code looks
933*5fc40de0SRobert Mustacchi 		 * like reasonable C style.
934*5fc40de0SRobert Mustacchi 		 */
935*5fc40de0SRobert Mustacchi 		if (p != map->cmap_procs) {
936*5fc40de0SRobert Mustacchi 			if (fputs("\t    ", f) == -1) {
937*5fc40de0SRobert Mustacchi 				return (B_FALSE);
938*5fc40de0SRobert Mustacchi 			}
939*5fc40de0SRobert Mustacchi 		}
940*5fc40de0SRobert Mustacchi 
941*5fc40de0SRobert Mustacchi 		if (p->cproc_nsteps > 0) {
942*5fc40de0SRobert Mustacchi 			uint_t i;
943*5fc40de0SRobert Mustacchi 
944*5fc40de0SRobert Mustacchi 			if (fprintf(f, "(model == 0x%x &&\n\t    (",
945*5fc40de0SRobert Mustacchi 			    p->cproc_model) == -1) {
946*5fc40de0SRobert Mustacchi 				return (B_FALSE);
947*5fc40de0SRobert Mustacchi 			}
948*5fc40de0SRobert Mustacchi 
949*5fc40de0SRobert Mustacchi 			for (i = 0; i < p->cproc_nsteps; i++) {
950*5fc40de0SRobert Mustacchi 				if (fprintf(f, "stepping == 0x%x%s",
951*5fc40de0SRobert Mustacchi 				    p->cproc_steppings[i],
952*5fc40de0SRobert Mustacchi 				    i + 1 != p->cproc_nsteps ?
953*5fc40de0SRobert Mustacchi 				    " ||\n\t    " : "") == -1) {
954*5fc40de0SRobert Mustacchi 					return (B_FALSE);
955*5fc40de0SRobert Mustacchi 				}
956*5fc40de0SRobert Mustacchi 			}
957*5fc40de0SRobert Mustacchi 
958*5fc40de0SRobert Mustacchi 			if (fputs("))", f) == -1) {
959*5fc40de0SRobert Mustacchi 				return (B_FALSE);
960*5fc40de0SRobert Mustacchi 			}
961*5fc40de0SRobert Mustacchi 		} else if (fprintf(f, "model == 0x%x", p->cproc_model) == -1) {
962*5fc40de0SRobert Mustacchi 			return (B_FALSE);
963*5fc40de0SRobert Mustacchi 		}
964*5fc40de0SRobert Mustacchi 
965*5fc40de0SRobert Mustacchi 		if (fprintf(f, "%s\n",
966*5fc40de0SRobert Mustacchi 		    p->cproc_next != NULL ? " ||" : ") {") == -1) {
967*5fc40de0SRobert Mustacchi 			return (B_FALSE);
968*5fc40de0SRobert Mustacchi 		}
969*5fc40de0SRobert Mustacchi 	}
970*5fc40de0SRobert Mustacchi 
971*5fc40de0SRobert Mustacchi 	if (fprintf(f, "\t\t\treturn (pcbe_core_events_%s);\n",
972*5fc40de0SRobert Mustacchi 	    map->cmap_name) == -1) {
973*5fc40de0SRobert Mustacchi 		return (B_FALSE);
974*5fc40de0SRobert Mustacchi 	}
975*5fc40de0SRobert Mustacchi 
976*5fc40de0SRobert Mustacchi 	return (B_TRUE);
977*5fc40de0SRobert Mustacchi }
978*5fc40de0SRobert Mustacchi 
97953548f91SRobert Mustacchi /*
98053548f91SRobert Mustacchi  * Generate a header file that declares all of these arrays and provide a map
98153548f91SRobert Mustacchi  * for models to the corresponding table to use.
98253548f91SRobert Mustacchi  */
98353548f91SRobert Mustacchi static void
98453548f91SRobert Mustacchi cpcgen_common_files(int dirfd)
98553548f91SRobert Mustacchi {
98653548f91SRobert Mustacchi 	const char *fname = "core_pcbe_cpcgen.h";
98753548f91SRobert Mustacchi 	char *tmpname;
98853548f91SRobert Mustacchi 	int fd;
98953548f91SRobert Mustacchi 	FILE *f;
99053548f91SRobert Mustacchi 	cpc_map_t *map;
99153548f91SRobert Mustacchi 
99253548f91SRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
99353548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
99453548f91SRobert Mustacchi 	}
99553548f91SRobert Mustacchi 
99653548f91SRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
99753548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
99853548f91SRobert Mustacchi 		    tmpname);
99953548f91SRobert Mustacchi 	}
100053548f91SRobert Mustacchi 
100153548f91SRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
100253548f91SRobert Mustacchi 		int e = errno;
100353548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
100453548f91SRobert Mustacchi 		errno = e;
100553548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
100653548f91SRobert Mustacchi 	}
100753548f91SRobert Mustacchi 
100853548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) {
100953548f91SRobert Mustacchi 		int e = errno;
101053548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
101153548f91SRobert Mustacchi 		errno = e;
101253548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
101353548f91SRobert Mustacchi 		    "for %s", fname);
101453548f91SRobert Mustacchi 	}
101553548f91SRobert Mustacchi 
101653548f91SRobert Mustacchi 	if (fprintf(f, "#ifndef _CORE_PCBE_CPCGEN_H\n"
101753548f91SRobert Mustacchi 	    "#define\t_CORE_PCBE_CPCGEN_H\n"
101853548f91SRobert Mustacchi 	    "\n"
101953548f91SRobert Mustacchi 	    "#ifdef __cplusplus\n"
102053548f91SRobert Mustacchi 	    "extern \"C\" {\n"
102153548f91SRobert Mustacchi 	    "#endif\n"
102253548f91SRobert Mustacchi 	    "\n"
1023*5fc40de0SRobert Mustacchi 	    "extern const struct events_table_t *core_cpcgen_table(uint_t, "
1024*5fc40de0SRobert Mustacchi 	    "uint_t);\n"
102553548f91SRobert Mustacchi 	    "\n") == -1) {
102653548f91SRobert Mustacchi 		int e = errno;
102753548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
102853548f91SRobert Mustacchi 		errno = e;
102953548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
103053548f91SRobert Mustacchi 		    "temporary file for %s", fname);
103153548f91SRobert Mustacchi 	}
103253548f91SRobert Mustacchi 
103353548f91SRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
103453548f91SRobert Mustacchi 		if (fprintf(f, "extern const struct events_table_t "
103553548f91SRobert Mustacchi 		    "pcbe_core_events_%s[];\n", map->cmap_name) == -1) {
103653548f91SRobert Mustacchi 			int e = errno;
103753548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
103853548f91SRobert Mustacchi 			errno = e;
103953548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write entry to "
104053548f91SRobert Mustacchi 			    "temporary file for %s", fname);
104153548f91SRobert Mustacchi 		}
104253548f91SRobert Mustacchi 	}
104353548f91SRobert Mustacchi 
104453548f91SRobert Mustacchi 	if (fprintf(f, "\n"
104553548f91SRobert Mustacchi 	    "#ifdef __cplusplus\n"
104653548f91SRobert Mustacchi 	    "}\n"
104753548f91SRobert Mustacchi 	    "#endif\n"
104853548f91SRobert Mustacchi 	    "\n"
104953548f91SRobert Mustacchi 	    "#endif /* _CORE_PCBE_CPCGEN_H */\n") == -1) {
105053548f91SRobert Mustacchi 		int e = errno;
105153548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
105253548f91SRobert Mustacchi 		errno = e;
105353548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
105453548f91SRobert Mustacchi 		    "temporary file for %s", fname);
105553548f91SRobert Mustacchi 	}
105653548f91SRobert Mustacchi 
105753548f91SRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
105853548f91SRobert Mustacchi 		int e = errno;
105953548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
106053548f91SRobert Mustacchi 		errno = e;
106153548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
106253548f91SRobert Mustacchi 	}
106353548f91SRobert Mustacchi 
106453548f91SRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
106553548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
106653548f91SRobert Mustacchi 		    tmpname);
106753548f91SRobert Mustacchi 	}
106853548f91SRobert Mustacchi 
106953548f91SRobert Mustacchi 	free(tmpname);
107053548f91SRobert Mustacchi 
107153548f91SRobert Mustacchi 	/* Now again for the .c file. */
107253548f91SRobert Mustacchi 	fname = "core_pcbe_cpcgen.c";
107353548f91SRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
107453548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
107553548f91SRobert Mustacchi 	}
107653548f91SRobert Mustacchi 
107753548f91SRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
107853548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
107953548f91SRobert Mustacchi 		    tmpname);
108053548f91SRobert Mustacchi 	}
108153548f91SRobert Mustacchi 
108253548f91SRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
108353548f91SRobert Mustacchi 		int e = errno;
108453548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
108553548f91SRobert Mustacchi 		errno = e;
108653548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
108753548f91SRobert Mustacchi 	}
108853548f91SRobert Mustacchi 
108953548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) {
109053548f91SRobert Mustacchi 		int e = errno;
109153548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
109253548f91SRobert Mustacchi 		errno = e;
109353548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
109453548f91SRobert Mustacchi 		    "for %s", fname);
109553548f91SRobert Mustacchi 	}
109653548f91SRobert Mustacchi 
109753548f91SRobert Mustacchi 	if (fprintf(f, "#include <core_pcbe_table.h>\n"
109853548f91SRobert Mustacchi 	    "#include <sys/null.h>\n"
109953548f91SRobert Mustacchi 	    "#include \"core_pcbe_cpcgen.h\"\n"
110053548f91SRobert Mustacchi 	    "\n"
110153548f91SRobert Mustacchi 	    "const struct events_table_t *\n"
1102*5fc40de0SRobert Mustacchi 	    "core_cpcgen_table(uint_t model, uint_t stepping)\n"
1103*5fc40de0SRobert Mustacchi 	    "{\n") == -1) {
110453548f91SRobert Mustacchi 		int e = errno;
110553548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
110653548f91SRobert Mustacchi 		errno = e;
110753548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
110853548f91SRobert Mustacchi 		    "temporary file for %s", fname);
110953548f91SRobert Mustacchi 	}
111053548f91SRobert Mustacchi 
111153548f91SRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
1112*5fc40de0SRobert Mustacchi 		if (!cpcgen_generate_map(f, map, map == cpcgen_maps)) {
111353548f91SRobert Mustacchi 			int e = errno;
111453548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
111553548f91SRobert Mustacchi 			errno = e;
1116*5fc40de0SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write to temporary "
1117*5fc40de0SRobert Mustacchi 			    "file for %s", fname);
111853548f91SRobert Mustacchi 		}
111953548f91SRobert Mustacchi 	}
112053548f91SRobert Mustacchi 
1121*5fc40de0SRobert Mustacchi 	if (fprintf(f, "\t} else {\n"
112253548f91SRobert Mustacchi 	    "\t\t\treturn (NULL);\n"
112353548f91SRobert Mustacchi 	    "\t}\n"
112453548f91SRobert Mustacchi 	    "}\n") == -1) {
112553548f91SRobert Mustacchi 		int e = errno;
112653548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
112753548f91SRobert Mustacchi 		errno = e;
112853548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
112953548f91SRobert Mustacchi 		    "temporary file for %s", fname);
113053548f91SRobert Mustacchi 	}
113153548f91SRobert Mustacchi 
113253548f91SRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
113353548f91SRobert Mustacchi 		int e = errno;
113453548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
113553548f91SRobert Mustacchi 		errno = e;
113653548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
113753548f91SRobert Mustacchi 	}
113853548f91SRobert Mustacchi 
113953548f91SRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
114053548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
114153548f91SRobert Mustacchi 		    tmpname);
114253548f91SRobert Mustacchi 	}
114353548f91SRobert Mustacchi 
114453548f91SRobert Mustacchi 	free(tmpname);
114553548f91SRobert Mustacchi }
114653548f91SRobert Mustacchi 
114753548f91SRobert Mustacchi /*
114853548f91SRobert Mustacchi  * Look at a rule to determine whether or not we should consider including it or
114953548f91SRobert Mustacchi  * not. At this point we've already filtered things such that we only get core
115053548f91SRobert Mustacchi  * events.
115153548f91SRobert Mustacchi  *
115253548f91SRobert Mustacchi  * To consider an entry, we currently apply the following criteria:
115353548f91SRobert Mustacchi  *
115453548f91SRobert Mustacchi  * - The MSRIndex and MSRValue are zero. Programming additional MSRs is no
115553548f91SRobert Mustacchi  *   supported right now.
115653548f91SRobert Mustacchi  * - TakenAlone is non-zero, which means that it cannot run at the same time as
115753548f91SRobert Mustacchi  *   another field.
115853548f91SRobert Mustacchi  * - Offcore is one, indicating that it is off the core and we need to figure
115953548f91SRobert Mustacchi  *   out if we can support this.
116053548f91SRobert Mustacchi  * - If the counter is fixed, don't use it for now.
116153548f91SRobert Mustacchi  * - If more than one value is specified in the EventCode or UMask values
116253548f91SRobert Mustacchi  */
116353548f91SRobert Mustacchi static boolean_t
116453548f91SRobert Mustacchi cpcgen_skip_entry(nvlist_t *nvl, const char *path, uint_t ent)
116553548f91SRobert Mustacchi {
116653548f91SRobert Mustacchi 	char *event, *msridx, *msrval, *taken, *offcore, *counter;
116753548f91SRobert Mustacchi 	char *ecode, *umask;
116853548f91SRobert Mustacchi 
116953548f91SRobert Mustacchi 	/*
117053548f91SRobert Mustacchi 	 * Require EventName, it's kind of useless without that.
117153548f91SRobert Mustacchi 	 */
117253548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
117353548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "Found event without 'EventName' property "
117453548f91SRobert Mustacchi 		    "in %s, entry %u", path, ent);
117553548f91SRobert Mustacchi 	}
117653548f91SRobert Mustacchi 
117753548f91SRobert Mustacchi 	/*
117853548f91SRobert Mustacchi 	 * If we can't find an expected value, whine about it.
117953548f91SRobert Mustacchi 	 */
118053548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "MSRIndex", &msridx) != 0 ||
118153548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "MSRValue", &msrval) != 0 ||
118253548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0 ||
118353548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
118453548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
118553548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "Offcore", &offcore) != 0) {
118653548f91SRobert Mustacchi 		warnx("Skipping event %s (index %u) from %s, missing required "
118753548f91SRobert Mustacchi 		    "property", event, ent, path);
118853548f91SRobert Mustacchi 		return (B_TRUE);
118953548f91SRobert Mustacchi 	}
119053548f91SRobert Mustacchi 
119153548f91SRobert Mustacchi 	/*
119253548f91SRobert Mustacchi 	 * MSRIndex and MSRvalue comes as either "0" or "0x00".
119353548f91SRobert Mustacchi 	 */
119453548f91SRobert Mustacchi 	if ((strcmp(msridx, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
119553548f91SRobert Mustacchi 	    (strcmp(msrval, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
119653548f91SRobert Mustacchi 	    strcmp(offcore, "0") != 0 || strchr(ecode, ',') != NULL ||
119753548f91SRobert Mustacchi 	    strchr(umask, ',') != NULL) {
119853548f91SRobert Mustacchi 		return (B_TRUE);
119953548f91SRobert Mustacchi 	}
120053548f91SRobert Mustacchi 
120153548f91SRobert Mustacchi 	/*
120253548f91SRobert Mustacchi 	 * Unfortunately, not everything actually has "TakenAlone". If it
120353548f91SRobert Mustacchi 	 * doesn't, we assume that it doesn't have to be.
120453548f91SRobert Mustacchi 	 */
120553548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "TakenAlone", &taken) == 0 &&
120653548f91SRobert Mustacchi 	    strcmp(taken, "0") != 0) {
120753548f91SRobert Mustacchi 		return (B_TRUE);
120853548f91SRobert Mustacchi 	}
120953548f91SRobert Mustacchi 
121053548f91SRobert Mustacchi 
121153548f91SRobert Mustacchi 	if (strncasecmp(counter, "fixed", strlen("fixed")) == 0)
121253548f91SRobert Mustacchi 		return (B_TRUE);
121353548f91SRobert Mustacchi 
121453548f91SRobert Mustacchi 	return (B_FALSE);
121553548f91SRobert Mustacchi }
121653548f91SRobert Mustacchi 
121753548f91SRobert Mustacchi /*
121853548f91SRobert Mustacchi  * For each processor family, generate a data file that contains all of the
121953548f91SRobert Mustacchi  * events that we support. Also generate a header that can be included that
122053548f91SRobert Mustacchi  * declares all of the tables.
122153548f91SRobert Mustacchi  */
122253548f91SRobert Mustacchi static void
122353548f91SRobert Mustacchi cpcgen_gen(int dirfd)
122453548f91SRobert Mustacchi {
122553548f91SRobert Mustacchi 	cpc_map_t *map = cpcgen_maps;
122653548f91SRobert Mustacchi 
122753548f91SRobert Mustacchi 	if (map == NULL) {
122853548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "no platforms found or matched");
122953548f91SRobert Mustacchi 	}
123053548f91SRobert Mustacchi 
123153548f91SRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
123253548f91SRobert Mustacchi 		int fd, ret;
123353548f91SRobert Mustacchi 		FILE *f;
123453548f91SRobert Mustacchi 		char *tmpname, *name;
123553548f91SRobert Mustacchi 		uint32_t length, i;
123653548f91SRobert Mustacchi 
123753548f91SRobert Mustacchi 		if ((name = cpcgen_ops.cgen_op_name(map)) == NULL) {
123853548f91SRobert Mustacchi 			exit(EXIT_FAILURE);
123953548f91SRobert Mustacchi 		}
124053548f91SRobert Mustacchi 
124153548f91SRobert Mustacchi 		if (asprintf(&tmpname, ".%s.%d", name, getpid()) == -1) {
124253548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to construct temporary file "
124353548f91SRobert Mustacchi 			    "name");
124453548f91SRobert Mustacchi 		}
124553548f91SRobert Mustacchi 
124653548f91SRobert Mustacchi 		if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0444)) < 0) {
124753548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to create temporary file %s",
124853548f91SRobert Mustacchi 			    tmpname);
124953548f91SRobert Mustacchi 		}
125053548f91SRobert Mustacchi 
125153548f91SRobert Mustacchi 		if ((f = fdopen(fd, "w")) == NULL) {
125253548f91SRobert Mustacchi 			int e = errno;
125353548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
125453548f91SRobert Mustacchi 			errno = e;
125553548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to fdopen temporary file");
125653548f91SRobert Mustacchi 		}
125753548f91SRobert Mustacchi 
125853548f91SRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_before(f, map)) {
125953548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
126053548f91SRobert Mustacchi 			exit(EXIT_FAILURE);
126153548f91SRobert Mustacchi 		}
126253548f91SRobert Mustacchi 
126353548f91SRobert Mustacchi 		/*
126453548f91SRobert Mustacchi 		 * Iterate over array contents.
126553548f91SRobert Mustacchi 		 */
126653548f91SRobert Mustacchi 		if ((ret = nvlist_lookup_uint32(map->cmap_data, "length",
126753548f91SRobert Mustacchi 		    &length)) != 0) {
126853548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to look up length property "
126953548f91SRobert Mustacchi 			    "in parsed data for %s: %s", map->cmap_path,
127053548f91SRobert Mustacchi 			    strerror(ret));
127153548f91SRobert Mustacchi 		}
127253548f91SRobert Mustacchi 
127353548f91SRobert Mustacchi 		for (i = 0; i < length; i++) {
127453548f91SRobert Mustacchi 			nvlist_t *nvl;
127553548f91SRobert Mustacchi 			char num[64];
127653548f91SRobert Mustacchi 
127753548f91SRobert Mustacchi 			(void) snprintf(num, sizeof (num), "%u", i);
127853548f91SRobert Mustacchi 			if ((ret = nvlist_lookup_nvlist(map->cmap_data,
127953548f91SRobert Mustacchi 			    num, &nvl)) != 0) {
128053548f91SRobert Mustacchi 				errx(EXIT_FAILURE, "failed to look up array "
128153548f91SRobert Mustacchi 				    "entry %u in parsed data for %s: %s", i,
128253548f91SRobert Mustacchi 				    map->cmap_path, strerror(ret));
128353548f91SRobert Mustacchi 			}
128453548f91SRobert Mustacchi 
128553548f91SRobert Mustacchi 			if (cpcgen_skip_entry(nvl, map->cmap_path, i))
128653548f91SRobert Mustacchi 				continue;
128753548f91SRobert Mustacchi 
128853548f91SRobert Mustacchi 			if (!cpcgen_ops.cgen_op_event(f, nvl, map->cmap_path,
128953548f91SRobert Mustacchi 			    i)) {
129053548f91SRobert Mustacchi 				(void) unlinkat(dirfd, tmpname, 0);
129153548f91SRobert Mustacchi 				exit(EXIT_FAILURE);
129253548f91SRobert Mustacchi 			}
129353548f91SRobert Mustacchi 		}
129453548f91SRobert Mustacchi 
129553548f91SRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_after(f, map)) {
129653548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
129753548f91SRobert Mustacchi 			exit(EXIT_FAILURE);
129853548f91SRobert Mustacchi 		}
129953548f91SRobert Mustacchi 
130053548f91SRobert Mustacchi 		if (fflush(f) != 0 || fclose(f) != 0) {
130153548f91SRobert Mustacchi 			int e = errno;
130253548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
130353548f91SRobert Mustacchi 			errno = e;
130453548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to flush and close "
130553548f91SRobert Mustacchi 			    "temporary file");
130653548f91SRobert Mustacchi 		}
130753548f91SRobert Mustacchi 
130853548f91SRobert Mustacchi 		if (renameat(dirfd, tmpname, dirfd, name) != 0) {
130953548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to rename temporary file %s",
131053548f91SRobert Mustacchi 			    tmpname);
131153548f91SRobert Mustacchi 		}
131253548f91SRobert Mustacchi 
131353548f91SRobert Mustacchi 		free(name);
131453548f91SRobert Mustacchi 		free(tmpname);
131553548f91SRobert Mustacchi 	}
131653548f91SRobert Mustacchi }
131753548f91SRobert Mustacchi 
131853548f91SRobert Mustacchi static void
131953548f91SRobert Mustacchi cpcgen_usage(const char *fmt, ...)
132053548f91SRobert Mustacchi {
132153548f91SRobert Mustacchi 	if (fmt != NULL) {
132253548f91SRobert Mustacchi 		va_list ap;
132353548f91SRobert Mustacchi 
132453548f91SRobert Mustacchi 		(void) fprintf(stderr, "%s: ", cpcgen_progname);
132553548f91SRobert Mustacchi 		va_start(ap, fmt);
132653548f91SRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
132753548f91SRobert Mustacchi 		va_end(ap);
132853548f91SRobert Mustacchi 	}
132953548f91SRobert Mustacchi 
133053548f91SRobert Mustacchi 	(void) fprintf(stderr, "Usage: %s -a|-p platform -c|-H|-m -d datadir "
133153548f91SRobert Mustacchi 	    "-o outdir\n"
133253548f91SRobert Mustacchi 	    "\n"
133353548f91SRobert Mustacchi 	    "\t-a  generate data for all platforms\n"
133453548f91SRobert Mustacchi 	    "\t-c  generate C file for CPC\n"
133553548f91SRobert Mustacchi 	    "\t-d  specify the directory containt perfmon data\n"
133653548f91SRobert Mustacchi 	    "\t-h  generate header file and common files\n"
133753548f91SRobert Mustacchi 	    "\t-m  generate manual pages for CPC data\n"
133853548f91SRobert Mustacchi 	    "\t-o  outut files in directory outdir\n"
133953548f91SRobert Mustacchi 	    "\t-p  generate data for a specified platform\n",
134053548f91SRobert Mustacchi 	    cpcgen_progname);
134153548f91SRobert Mustacchi }
134253548f91SRobert Mustacchi 
134353548f91SRobert Mustacchi int
134453548f91SRobert Mustacchi main(int argc, char *argv[])
134553548f91SRobert Mustacchi {
134653548f91SRobert Mustacchi 	int c, outdirfd;
134753548f91SRobert Mustacchi 	boolean_t do_mpage = B_FALSE, do_cfile = B_FALSE, do_header = B_FALSE,
134853548f91SRobert Mustacchi 	    do_all = B_FALSE;
134953548f91SRobert Mustacchi 	const char *datadir = NULL, *outdir = NULL, *platform = NULL;
135053548f91SRobert Mustacchi 	uint_t count = 0;
135153548f91SRobert Mustacchi 
135253548f91SRobert Mustacchi 	cpcgen_progname = basename(argv[0]);
135353548f91SRobert Mustacchi 
135453548f91SRobert Mustacchi 	while ((c = getopt(argc, argv, ":acd:hHmo:p:")) != -1) {
135553548f91SRobert Mustacchi 		switch (c) {
135653548f91SRobert Mustacchi 		case 'a':
135753548f91SRobert Mustacchi 			do_all = B_TRUE;
135853548f91SRobert Mustacchi 			break;
135953548f91SRobert Mustacchi 		case 'c':
136053548f91SRobert Mustacchi 			do_cfile = B_TRUE;
136153548f91SRobert Mustacchi 			break;
136253548f91SRobert Mustacchi 		case 'd':
136353548f91SRobert Mustacchi 			datadir = optarg;
136453548f91SRobert Mustacchi 			break;
136553548f91SRobert Mustacchi 		case 'm':
136653548f91SRobert Mustacchi 			do_mpage = B_TRUE;
136753548f91SRobert Mustacchi 			break;
136853548f91SRobert Mustacchi 		case 'H':
136953548f91SRobert Mustacchi 			do_header = B_TRUE;
137053548f91SRobert Mustacchi 			break;
137153548f91SRobert Mustacchi 		case 'o':
137253548f91SRobert Mustacchi 			outdir = optarg;
137353548f91SRobert Mustacchi 			break;
137453548f91SRobert Mustacchi 		case 'p':
137553548f91SRobert Mustacchi 			platform = optarg;
137653548f91SRobert Mustacchi 			break;
137753548f91SRobert Mustacchi 		case ':':
137853548f91SRobert Mustacchi 			cpcgen_usage("Option -%c requires an operand\n",
137953548f91SRobert Mustacchi 			    optopt);
138053548f91SRobert Mustacchi 			return (2);
138153548f91SRobert Mustacchi 		case '?':
138253548f91SRobert Mustacchi 			cpcgen_usage("Unknown option: -%c\n", optopt);
138353548f91SRobert Mustacchi 			return (2);
138453548f91SRobert Mustacchi 		case 'h':
138553548f91SRobert Mustacchi 		default:
138653548f91SRobert Mustacchi 			cpcgen_usage(NULL);
138753548f91SRobert Mustacchi 			return (2);
138853548f91SRobert Mustacchi 		}
138953548f91SRobert Mustacchi 	}
139053548f91SRobert Mustacchi 
139153548f91SRobert Mustacchi 	count = 0;
139253548f91SRobert Mustacchi 	if (do_mpage)
139353548f91SRobert Mustacchi 		count++;
139453548f91SRobert Mustacchi 	if (do_cfile)
139553548f91SRobert Mustacchi 		count++;
139653548f91SRobert Mustacchi 	if (do_header)
139753548f91SRobert Mustacchi 		count++;
139853548f91SRobert Mustacchi 	if (count > 1) {
139953548f91SRobert Mustacchi 		cpcgen_usage("Only one of -c, -h, and -m may be specified\n");
140053548f91SRobert Mustacchi 		return (2);
140153548f91SRobert Mustacchi 	} else if (count == 0) {
140253548f91SRobert Mustacchi 		cpcgen_usage("One of -c, -h, and -m is required\n");
140353548f91SRobert Mustacchi 		return (2);
140453548f91SRobert Mustacchi 	}
140553548f91SRobert Mustacchi 
140653548f91SRobert Mustacchi 	count = 0;
140753548f91SRobert Mustacchi 	if (do_all)
140853548f91SRobert Mustacchi 		count++;
140953548f91SRobert Mustacchi 	if (platform != NULL)
141053548f91SRobert Mustacchi 		count++;
141153548f91SRobert Mustacchi 	if (count > 1) {
141253548f91SRobert Mustacchi 		cpcgen_usage("Only one of -a and -p may be specified\n");
141353548f91SRobert Mustacchi 		return (2);
141453548f91SRobert Mustacchi 	} else if (count == 0) {
141553548f91SRobert Mustacchi 		cpcgen_usage("One of -a and -p is required\n");
141653548f91SRobert Mustacchi 		return (2);
141753548f91SRobert Mustacchi 	}
141853548f91SRobert Mustacchi 
141953548f91SRobert Mustacchi 
142053548f91SRobert Mustacchi 	if (outdir == NULL) {
142153548f91SRobert Mustacchi 		cpcgen_usage("Missing required output directory (-o)\n");
142253548f91SRobert Mustacchi 		return (2);
142353548f91SRobert Mustacchi 	}
142453548f91SRobert Mustacchi 
142553548f91SRobert Mustacchi 	if ((outdirfd = open(outdir, O_RDONLY)) < 0) {
142653548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open output directory %s", outdir);
142753548f91SRobert Mustacchi 	}
142853548f91SRobert Mustacchi 
142953548f91SRobert Mustacchi 	if (datadir == NULL) {
143053548f91SRobert Mustacchi 		cpcgen_usage("Missing required data directory (-d)\n");
143153548f91SRobert Mustacchi 		return (2);
143253548f91SRobert Mustacchi 	}
143353548f91SRobert Mustacchi 
143453548f91SRobert Mustacchi 	cpcgen_read_mapfile(datadir, platform);
143553548f91SRobert Mustacchi 
143653548f91SRobert Mustacchi 	if (do_header) {
143753548f91SRobert Mustacchi 		cpcgen_common_files(outdirfd);
143853548f91SRobert Mustacchi 		return (0);
143953548f91SRobert Mustacchi 	}
144053548f91SRobert Mustacchi 
144153548f91SRobert Mustacchi 	if (do_mpage) {
144253548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_name = cpcgen_manual_name;
144353548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_before = cpcgen_manual_file_before;
144453548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_after = cpcgen_manual_file_after;
144553548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_event = cpcgen_manual_event;
144653548f91SRobert Mustacchi 	}
144753548f91SRobert Mustacchi 
144853548f91SRobert Mustacchi 	if (do_cfile) {
144953548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_name = cpcgen_cfile_name;
145053548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_before = cpcgen_cfile_file_before;
145153548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_after = cpcgen_cfile_file_after;
145253548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_event = cpcgen_cfile_event;
145353548f91SRobert Mustacchi 	}
145453548f91SRobert Mustacchi 
145553548f91SRobert Mustacchi 
145653548f91SRobert Mustacchi 	cpcgen_gen(outdirfd);
145753548f91SRobert Mustacchi 
145853548f91SRobert Mustacchi 	return (0);
145953548f91SRobert Mustacchi }
1460