xref: /titanic_50/usr/src/tools/cpcgen/cpcgen.c (revision 1ad658ab148b4674f2e09f730d0212e7479bd70b)
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 /*
13*1ad658abSJohn 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
4053548f91SRobert Mustacchi 
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;
4653548f91SRobert Mustacchi } cpc_proc_t;
4753548f91SRobert Mustacchi 
4853548f91SRobert Mustacchi typedef enum cpc_file_type {
4953548f91SRobert Mustacchi 	CPC_FILE_CORE		= 1 << 0,
5053548f91SRobert Mustacchi 	CPC_FILE_OFF_CORE	= 1 << 1,
5153548f91SRobert Mustacchi 	CPC_FILE_UNCORE		= 1 << 2,
5253548f91SRobert Mustacchi 	CPC_FILE_FP_MATH	= 1 << 3,
5353548f91SRobert Mustacchi 	CPC_FILE_UNCORE_EXP	= 1 << 4
5453548f91SRobert Mustacchi } cpc_type_t;
5553548f91SRobert Mustacchi 
5653548f91SRobert Mustacchi typedef struct cpc_map {
5753548f91SRobert Mustacchi 	struct cpc_map	*cmap_next;
5853548f91SRobert Mustacchi 	cpc_type_t	cmap_type;
5953548f91SRobert Mustacchi 	nvlist_t	*cmap_data;
6053548f91SRobert Mustacchi 	char		*cmap_path;
6153548f91SRobert Mustacchi 	const char	*cmap_name;
6253548f91SRobert Mustacchi 	cpc_proc_t	*cmap_procs;
6353548f91SRobert Mustacchi } cpc_map_t;
6453548f91SRobert Mustacchi 
6553548f91SRobert Mustacchi typedef struct cpc_whitelist {
6653548f91SRobert Mustacchi 	const char	*cwhite_short;
6753548f91SRobert Mustacchi 	const char	*cwhite_human;
6853548f91SRobert Mustacchi 	uint_t		cwhite_mask;
6953548f91SRobert Mustacchi } cpc_whitelist_t;
7053548f91SRobert Mustacchi 
7153548f91SRobert Mustacchi /*
7253548f91SRobert Mustacchi  * List of architectures that we support generating this data for. This is done
7353548f91SRobert Mustacchi  * so that processors that illumos doesn't support or run on aren't generated
7453548f91SRobert Mustacchi  * (generally the Xeon Phi).
7553548f91SRobert Mustacchi  */
7653548f91SRobert Mustacchi static cpc_whitelist_t cpcgen_whitelist[] = {
7753548f91SRobert Mustacchi 	/* Nehalem */
7853548f91SRobert Mustacchi 	{ "NHM-EP", "nhm_ep", CPC_FILE_CORE },
7953548f91SRobert Mustacchi 	{ "NHM-EX", "nhm_ex", CPC_FILE_CORE },
8053548f91SRobert Mustacchi 	/* Westmere */
8153548f91SRobert Mustacchi 	{ "WSM-EP-DP", "wsm_ep_dp", CPC_FILE_CORE },
8253548f91SRobert Mustacchi 	{ "WSM-EP-SP", "wsm_ep_sp", CPC_FILE_CORE },
8353548f91SRobert Mustacchi 	{ "WSM-EX", "wsm_ex", CPC_FILE_CORE },
8453548f91SRobert Mustacchi 	/* Sandy Bridge */
8553548f91SRobert Mustacchi 	{ "SNB", "snb", CPC_FILE_CORE },
8653548f91SRobert Mustacchi 	{ "JKT", "jkt", CPC_FILE_CORE },
8753548f91SRobert Mustacchi 	/* Ivy Bridge */
8853548f91SRobert Mustacchi 	{ "IVB", "ivb", CPC_FILE_CORE },
8953548f91SRobert Mustacchi 	{ "IVT", "ivt", CPC_FILE_CORE },
9053548f91SRobert Mustacchi 	/* Haswell */
9153548f91SRobert Mustacchi 	{ "HSW", "hsw", CPC_FILE_CORE },
9253548f91SRobert Mustacchi 	{ "HSX", "hsx", CPC_FILE_CORE },
9353548f91SRobert Mustacchi 	/* Broadwell */
9453548f91SRobert Mustacchi 	{ "BDW", "bdw", CPC_FILE_CORE },
9553548f91SRobert Mustacchi 	{ "BDW-DE", "bdw_de", CPC_FILE_CORE },
9653548f91SRobert Mustacchi 	{ "BDX", "bdx", CPC_FILE_CORE },
9753548f91SRobert Mustacchi 	/* Skylake */
9853548f91SRobert Mustacchi 	{ "SKL", "skl", CPC_FILE_CORE },
9953548f91SRobert Mustacchi 	{ "SKX", "skx", CPC_FILE_CORE },
10053548f91SRobert Mustacchi 	/* Atom */
10153548f91SRobert Mustacchi 	{ "BNL", "bnl", CPC_FILE_CORE },
10253548f91SRobert Mustacchi 	{ "SLM", "slm", CPC_FILE_CORE },
10353548f91SRobert Mustacchi 	{ "GLM", "glm", CPC_FILE_CORE },
10453548f91SRobert Mustacchi 	{ "GLP", "glp", CPC_FILE_CORE },
10553548f91SRobert Mustacchi 	{ NULL }
10653548f91SRobert Mustacchi };
10753548f91SRobert Mustacchi 
10853548f91SRobert Mustacchi typedef struct cpc_papi {
10953548f91SRobert Mustacchi 	const char	*cpapi_intc;
11053548f91SRobert Mustacchi 	const char	*cpapi_papi;
11153548f91SRobert Mustacchi } cpc_papi_t;
11253548f91SRobert Mustacchi 
11353548f91SRobert Mustacchi /*
11453548f91SRobert Mustacchi  * This table maps events with an Intel specific name to the corresponding PAPI
11553548f91SRobert Mustacchi  * name. There may be multiple INtel events which map to the same PAPI event.
11653548f91SRobert Mustacchi  * This is usually because different processors have different names for an
11753548f91SRobert Mustacchi  * event. We use the title as opposed to the event codes because those can
11853548f91SRobert Mustacchi  * change somewhat arbitrarily between processor generations.
11953548f91SRobert Mustacchi  */
12053548f91SRobert Mustacchi static cpc_papi_t cpcgen_papi_map[] = {
12153548f91SRobert Mustacchi 	{ "CPU_CLK_UNHALTED.THREAD_P", "PAPI_tot_cyc" },
12253548f91SRobert Mustacchi 	{ "INST_RETIRED.ANY_P", "PAPI_tot_ins" },
12353548f91SRobert Mustacchi 	{ "BR_INST_RETIRED.ALL_BRANCHES", "PAPI_br_ins" },
12453548f91SRobert Mustacchi 	{ "BR_MISP_RETIRED.ALL_BRANCHES", "PAPI_br_msp" },
12553548f91SRobert Mustacchi 	{ "BR_INST_RETIRED.CONDITIONAL", "PAPI_br_cn" },
12653548f91SRobert Mustacchi 	{ "CYCLE_ACTIVITY.CYCLES_L1D_MISS", "PAPI_l1_dcm" },
12753548f91SRobert Mustacchi 	{ "L1I.HITS", "PAPI_l1_ich" },
12853548f91SRobert Mustacchi 	{ "ICACHE.HIT", "PAPI_l1_ich" },
12953548f91SRobert Mustacchi 	{ "L1I.MISS", "PAPI_L1_icm" },
13053548f91SRobert Mustacchi 	{ "ICACHE.MISSES", "PAPI_l1_icm" },
13153548f91SRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_ica" },
13253548f91SRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_ica" },
13353548f91SRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_icr" },
13453548f91SRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_icr" },
13553548f91SRobert Mustacchi 	{ "L2_RQSTS.CODE_RD_MISS", "PAPI_l2_icm" },
13653548f91SRobert Mustacchi 	{ "L2_RQSTS.MISS", "PAPI_l2_tcm" },
13753548f91SRobert Mustacchi 	{ "ITLB_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_im" },
13853548f91SRobert Mustacchi 	{ "DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_dm" },
13953548f91SRobert Mustacchi 	{ "PAGE_WALKS.D_SIDE_WALKS", "PAPI_tlb_dm" },
14053548f91SRobert Mustacchi 	{ "PAGE_WALKS.I_SIDE_WALKS", "PAPI_tlb_im" },
14153548f91SRobert Mustacchi 	{ "PAGE_WALKS.WALKS", "PAPI_tlb_tl" },
14253548f91SRobert Mustacchi 	{ "INST_QUEUE_WRITES", "PAPI_tot_iis" },
14353548f91SRobert Mustacchi 	{ "MEM_INST_RETIRED.STORES" "PAPI_sr_ins" },
14453548f91SRobert Mustacchi 	{ "MEM_INST_RETIRED.LOADS" "PAPI_ld_ins" },
14553548f91SRobert Mustacchi 	{ NULL, NULL }
14653548f91SRobert Mustacchi };
14753548f91SRobert Mustacchi 
14853548f91SRobert Mustacchi typedef struct cpcgen_ops {
14953548f91SRobert Mustacchi 	char *(*cgen_op_name)(cpc_map_t *);
15053548f91SRobert Mustacchi 	boolean_t (*cgen_op_file_before)(FILE *, cpc_map_t *);
15153548f91SRobert Mustacchi 	boolean_t (*cgen_op_file_after)(FILE *, cpc_map_t *);
15253548f91SRobert Mustacchi 	boolean_t (*cgen_op_event)(FILE *, nvlist_t *, const char *, uint32_t);
15353548f91SRobert Mustacchi } cpcgen_ops_t;
15453548f91SRobert Mustacchi 
15553548f91SRobert Mustacchi static cpcgen_ops_t cpcgen_ops;
15653548f91SRobert Mustacchi static const char *cpcgen_mapfile = "/mapfile.csv";
15753548f91SRobert Mustacchi static const char *cpcgen_progname;
15853548f91SRobert Mustacchi static cpc_map_t *cpcgen_maps;
15953548f91SRobert Mustacchi 
16053548f91SRobert Mustacchi /*
16153548f91SRobert Mustacchi  * Constants used for generating data.
16253548f91SRobert Mustacchi  */
16353548f91SRobert Mustacchi /* BEGIN CSTYLED */
16453548f91SRobert Mustacchi static const char *cpcgen_cfile_header = ""
16553548f91SRobert Mustacchi "/*\n"
16653548f91SRobert Mustacchi " *  Copyright (c) 2018, Intel Corporation\n"
16753548f91SRobert Mustacchi " *  Copyright (c) 2018, Joyent, Inc\n"
16853548f91SRobert Mustacchi " *  All rights reserved.\n"
16953548f91SRobert Mustacchi " *\n"
17053548f91SRobert Mustacchi " *  Redistribution and use in source and binary forms, with or without\n"
17153548f91SRobert Mustacchi " *  modification, are permitted provided that the following conditions are met:\n"
17253548f91SRobert Mustacchi " * \n"
17353548f91SRobert Mustacchi " *   1. Redistributions of source code must retain the above copyright notice,\n"
17453548f91SRobert Mustacchi " *      this list of conditions and the following disclaimer.\n"
17553548f91SRobert Mustacchi " * \n"
17653548f91SRobert Mustacchi " *   2. Redistributions in binary form must reproduce the above copyright \n"
17753548f91SRobert Mustacchi " *      notice, this list of conditions and the following disclaimer in the\n"
17853548f91SRobert Mustacchi " *      documentation and/or other materials provided with the distribution.\n"
17953548f91SRobert Mustacchi " * \n"
18053548f91SRobert Mustacchi " *   3. Neither the name of the Intel Corporation nor the names of its \n"
18153548f91SRobert Mustacchi " *      contributors may be used to endorse or promote products derived from\n"
18253548f91SRobert Mustacchi " *      this software without specific prior written permission.\n"
18353548f91SRobert Mustacchi " *\n"
18453548f91SRobert Mustacchi " *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
18553548f91SRobert Mustacchi " *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
18653548f91SRobert Mustacchi " *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
18753548f91SRobert Mustacchi " *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
18853548f91SRobert Mustacchi " *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
18953548f91SRobert Mustacchi " *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
19053548f91SRobert Mustacchi " *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
19153548f91SRobert Mustacchi " *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
19253548f91SRobert Mustacchi " *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
19353548f91SRobert Mustacchi " *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
19453548f91SRobert Mustacchi " *  POSSIBILITY OF SUCH DAMAGE.\n"
19553548f91SRobert Mustacchi " *\n"
19653548f91SRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n"
19753548f91SRobert Mustacchi " * data/perfmon%s\n"
19853548f91SRobert Mustacchi " *\n"
19953548f91SRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
20053548f91SRobert Mustacchi " */\n"
20153548f91SRobert Mustacchi "\n";
20253548f91SRobert Mustacchi /* END CSTYLED */
20353548f91SRobert Mustacchi 
20453548f91SRobert Mustacchi static const char *cpcgen_cfile_table_start = ""
20553548f91SRobert Mustacchi "#include <core_pcbe_table.h>\n"
20653548f91SRobert Mustacchi "\n"
20753548f91SRobert Mustacchi "const struct events_table_t pcbe_core_events_%s[] = {\n";
20853548f91SRobert Mustacchi 
20953548f91SRobert Mustacchi static const char *cpcgen_cfile_table_end = ""
21053548f91SRobert Mustacchi "\t{ NT_END, 0, 0, \"\" }\n"
21153548f91SRobert Mustacchi "};\n";
21253548f91SRobert Mustacchi 
21353548f91SRobert Mustacchi /* BEGIN CSTYLED */
21453548f91SRobert Mustacchi static const char *cpcgen_manual_header = ""
21553548f91SRobert Mustacchi ".\\\" Copyright (c) 2018, Intel Corporation \n"
21653548f91SRobert Mustacchi ".\\\" Copyright (c) 2018, Joyent, Inc.\n"
21753548f91SRobert Mustacchi ".\\\" All rights reserved.\n"
21853548f91SRobert Mustacchi ".\\\"\n"
21953548f91SRobert Mustacchi ".\\\" Redistribution and use in source and binary forms, with or without \n"
22053548f91SRobert Mustacchi ".\\\" modification, are permitted provided that the following conditions are met:\n"
22153548f91SRobert Mustacchi ".\\\"\n"
22253548f91SRobert Mustacchi ".\\\"  1. Redistributions of source code must retain the above copyright notice,\n"
22353548f91SRobert Mustacchi ".\\\"     this list of conditions and the following disclaimer.\n"
22453548f91SRobert Mustacchi ".\\\"\n"
22553548f91SRobert Mustacchi ".\\\"  2. Redistributions in binary form must reproduce the above copyright\n"
22653548f91SRobert Mustacchi ".\\\"     notice, this list of conditions and the following disclaimer in the\n"
22753548f91SRobert Mustacchi ".\\\"     documentation and/or other materials provided with the distribution.\n"
22853548f91SRobert Mustacchi ".\\\"\n"
22953548f91SRobert Mustacchi ".\\\"  3. Neither the name of the Intel Corporation nor the names of its\n"
23053548f91SRobert Mustacchi ".\\\"     contributors may be used to endorse or promote products derived from\n"
23153548f91SRobert Mustacchi ".\\\"     this software without specific prior written permission.\n"
23253548f91SRobert Mustacchi ".\\\"\n"
23353548f91SRobert Mustacchi ".\\\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
23453548f91SRobert Mustacchi ".\\\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
23553548f91SRobert Mustacchi ".\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
23653548f91SRobert Mustacchi ".\\\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
23753548f91SRobert Mustacchi ".\\\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
23853548f91SRobert Mustacchi ".\\\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
23953548f91SRobert Mustacchi ".\\\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
24053548f91SRobert Mustacchi ".\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
24153548f91SRobert Mustacchi ".\\\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
24253548f91SRobert Mustacchi ".\\\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
24353548f91SRobert Mustacchi ".\\\" POSSIBILITY OF SUCH DAMAGE.\n"
24453548f91SRobert Mustacchi ".\\\"\n"
24553548f91SRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n"
24653548f91SRobert Mustacchi ".\\\" data/perfmon%s\n"
24753548f91SRobert Mustacchi ".\\\"\n"
24853548f91SRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n"
24953548f91SRobert Mustacchi ".\\\"\n"
25053548f91SRobert Mustacchi ".\\\" We would like to thank Intel for providing the perfmon data for use in\n"
25153548f91SRobert Mustacchi ".\\\" our manual pages.\n"
25253548f91SRobert Mustacchi ".Dd June 18, 2018\n"
25353548f91SRobert Mustacchi ".Dt %s_EVENTS 3CPC\n"
25453548f91SRobert Mustacchi ".Os\n"
25553548f91SRobert Mustacchi ".Sh NAME\n"
25653548f91SRobert Mustacchi ".Nm %s_events\n"
25753548f91SRobert Mustacchi ".Nd processor model specific performance counter events\n"
25853548f91SRobert Mustacchi ".Sh DESCRIPTION\n"
25953548f91SRobert Mustacchi "This manual page describes events specific to the following Intel CPU\n"
26053548f91SRobert Mustacchi "models and is derived from Intel's perfmon data.\n"
26153548f91SRobert Mustacchi "For more information, please consult the Intel Software Developer's Manual "
26253548f91SRobert Mustacchi "or Intel's perfmon website.\n"
26353548f91SRobert Mustacchi ".Pp\n"
26453548f91SRobert Mustacchi "CPU models described by this document:\n"
26553548f91SRobert Mustacchi ".Bl -bullet\n";
26653548f91SRobert Mustacchi /* END CSTYLED */
26753548f91SRobert Mustacchi 
26853548f91SRobert Mustacchi static const char *cpcgen_manual_data = ""
26953548f91SRobert Mustacchi ".El\n"
27053548f91SRobert Mustacchi ".Pp\n"
27153548f91SRobert Mustacchi "The following events are supported:\n"
27253548f91SRobert Mustacchi ".Bl -tag -width Sy\n";
27353548f91SRobert Mustacchi 
27453548f91SRobert Mustacchi static const char *cpcgen_manual_trailer = ""
27553548f91SRobert Mustacchi ".El\n"
27653548f91SRobert Mustacchi ".Sh SEE ALSO\n"
27753548f91SRobert Mustacchi ".Xr cpc 3CPC\n"
27853548f91SRobert Mustacchi ".Pp\n"
27953548f91SRobert Mustacchi ".Lk https://download.01.org/perfmon/index/";
28053548f91SRobert Mustacchi 
28153548f91SRobert Mustacchi static cpc_map_t *
28253548f91SRobert Mustacchi cpcgen_map_lookup(const char *path)
28353548f91SRobert Mustacchi {
28453548f91SRobert Mustacchi 	cpc_map_t *m;
28553548f91SRobert Mustacchi 
28653548f91SRobert Mustacchi 	for (m = cpcgen_maps; m != NULL; m = m->cmap_next) {
28753548f91SRobert Mustacchi 		if (strcmp(path, m->cmap_path) == 0) {
28853548f91SRobert Mustacchi 			return (m);
28953548f91SRobert Mustacchi 		}
29053548f91SRobert Mustacchi 	}
29153548f91SRobert Mustacchi 
29253548f91SRobert Mustacchi 	return (NULL);
29353548f91SRobert Mustacchi }
29453548f91SRobert Mustacchi 
29553548f91SRobert Mustacchi /*
29653548f91SRobert Mustacchi  * Parse a string of the form 'GenuineIntel-6-2E' and get out the family and
29753548f91SRobert Mustacchi  * model.
29853548f91SRobert Mustacchi  */
29953548f91SRobert Mustacchi static void
30053548f91SRobert Mustacchi cpcgen_parse_model(char *fsr, uint_t *family, uint_t *model)
30153548f91SRobert Mustacchi {
30253548f91SRobert Mustacchi 	const char *bstr = "GenuineIntel";
30353548f91SRobert Mustacchi 	const char *brand, *fam, *mod;
30453548f91SRobert Mustacchi 	char *last;
30553548f91SRobert Mustacchi 	long l;
30653548f91SRobert Mustacchi 
30753548f91SRobert Mustacchi 	if ((brand = strtok_r(fsr, "-", &last)) == NULL ||
30853548f91SRobert Mustacchi 	    (fam = strtok_r(NULL, "-", &last)) == NULL ||
30953548f91SRobert Mustacchi 	    (mod = strtok_r(NULL, "-", &last)) == NULL) {
31053548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse processor id \"%s\"", fsr);
31153548f91SRobert Mustacchi 	}
31253548f91SRobert Mustacchi 
31353548f91SRobert Mustacchi 	if (strcmp(bstr, brand) != 0) {
31453548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "brand string \"%s\" did not match \"%s\"",
31553548f91SRobert Mustacchi 		    brand, bstr);
31653548f91SRobert Mustacchi 	}
31753548f91SRobert Mustacchi 
31853548f91SRobert Mustacchi 	errno = 0;
31953548f91SRobert Mustacchi 	l = strtol(fam, &last, 16);
320*1ad658abSJohn Levon 	if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') {
32153548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse family \"%s\"", fam);
32253548f91SRobert Mustacchi 	}
32353548f91SRobert Mustacchi 	*family = (uint_t)l;
32453548f91SRobert Mustacchi 
32553548f91SRobert Mustacchi 	l = strtol(mod, &last, 16);
326*1ad658abSJohn Levon 	if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') {
32753548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse model \"%s\"", mod);
32853548f91SRobert Mustacchi 	}
32953548f91SRobert Mustacchi 	*model = (uint_t)l;
33053548f91SRobert Mustacchi }
33153548f91SRobert Mustacchi 
33253548f91SRobert Mustacchi static nvlist_t *
33353548f91SRobert Mustacchi cpcgen_read_datafile(const char *datadir, const char *file)
33453548f91SRobert Mustacchi {
33553548f91SRobert Mustacchi 	int fd;
33653548f91SRobert Mustacchi 	char *path;
33753548f91SRobert Mustacchi 	struct stat st;
33853548f91SRobert Mustacchi 	void *map;
33953548f91SRobert Mustacchi 	nvlist_t *nvl;
34053548f91SRobert Mustacchi 	nvlist_parse_json_error_t jerr;
34153548f91SRobert Mustacchi 
34253548f91SRobert Mustacchi 	if (asprintf(&path, "%s/%s", datadir, file) == -1) {
34353548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to data file %s",
34453548f91SRobert Mustacchi 		    file);
34553548f91SRobert Mustacchi 	}
34653548f91SRobert Mustacchi 
34753548f91SRobert Mustacchi 	if ((fd = open(path, O_RDONLY)) < 0) {
34853548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data file %s", path);
34953548f91SRobert Mustacchi 	}
35053548f91SRobert Mustacchi 
35153548f91SRobert Mustacchi 	if (fstat(fd, &st) != 0) {
35253548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to stat %s", path);
35353548f91SRobert Mustacchi 	}
35453548f91SRobert Mustacchi 
35553548f91SRobert Mustacchi 	if ((map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
35653548f91SRobert Mustacchi 	    fd, 0)) == MAP_FAILED) {
35753548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to mmap %s", path);
35853548f91SRobert Mustacchi 	}
35953548f91SRobert Mustacchi 
36053548f91SRobert Mustacchi 	if (nvlist_parse_json(map, st.st_size, &nvl, NVJSON_FORCE_INTEGER,
36153548f91SRobert Mustacchi 	    &jerr) != 0) {
36253548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse file %s at pos %ld: %s",
36353548f91SRobert Mustacchi 		    path, jerr.nje_pos, jerr.nje_message);
36453548f91SRobert Mustacchi 	}
36553548f91SRobert Mustacchi 
36653548f91SRobert Mustacchi 	if (munmap(map, st.st_size) != 0) {
36753548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to munmap %s", path);
36853548f91SRobert Mustacchi 	}
36953548f91SRobert Mustacchi 
37053548f91SRobert Mustacchi 	if (close(fd) != 0) {
37153548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to close data file %s", path);
37253548f91SRobert Mustacchi 	}
37353548f91SRobert Mustacchi 	free(path);
37453548f91SRobert Mustacchi 
37553548f91SRobert Mustacchi 	return (nvl);
37653548f91SRobert Mustacchi }
37753548f91SRobert Mustacchi 
37853548f91SRobert Mustacchi /*
37953548f91SRobert Mustacchi  * Check the whitelist to see if we should use this model.
38053548f91SRobert Mustacchi  */
38153548f91SRobert Mustacchi static const char *
38253548f91SRobert Mustacchi cpcgen_use_arch(const char *path, cpc_type_t type, const char *platform)
38353548f91SRobert Mustacchi {
38453548f91SRobert Mustacchi 	const char *slash;
38553548f91SRobert Mustacchi 	size_t len;
38653548f91SRobert Mustacchi 	uint_t i;
38753548f91SRobert Mustacchi 
38853548f91SRobert Mustacchi 	if (*path != '/') {
38953548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
39053548f91SRobert Mustacchi 		    "leading '/'", path);
39153548f91SRobert Mustacchi 	}
39253548f91SRobert Mustacchi 	if ((slash = strchr(path + 1, '/')) == NULL) {
39353548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
39453548f91SRobert Mustacchi 		    "second '/'", path);
39553548f91SRobert Mustacchi 	}
39653548f91SRobert Mustacchi 	/* Account for the last '/' character. */
39753548f91SRobert Mustacchi 	len = slash - path - 1;
39853548f91SRobert Mustacchi 	assert(len > 0);
39953548f91SRobert Mustacchi 
40053548f91SRobert Mustacchi 	for (i = 0; cpcgen_whitelist[i].cwhite_short != NULL; i++) {
40153548f91SRobert Mustacchi 		if (platform != NULL && strcasecmp(platform,
40253548f91SRobert Mustacchi 		    cpcgen_whitelist[i].cwhite_short) != 0)
40353548f91SRobert Mustacchi 			continue;
40453548f91SRobert Mustacchi 		if (strncmp(path + 1, cpcgen_whitelist[i].cwhite_short,
40553548f91SRobert Mustacchi 		    len) == 0 &&
40653548f91SRobert Mustacchi 		    (cpcgen_whitelist[i].cwhite_mask & type) == type) {
40753548f91SRobert Mustacchi 			return (cpcgen_whitelist[i].cwhite_human);
40853548f91SRobert Mustacchi 		}
40953548f91SRobert Mustacchi 	}
41053548f91SRobert Mustacchi 
41153548f91SRobert Mustacchi 	return (NULL);
41253548f91SRobert Mustacchi }
41353548f91SRobert Mustacchi 
41453548f91SRobert Mustacchi /*
41553548f91SRobert Mustacchi  * Read in the mapfile.csv that is used to map between processor families and
41653548f91SRobert Mustacchi  * parse this. Each line has a comma separated value.
41753548f91SRobert Mustacchi  */
41853548f91SRobert Mustacchi static void
41953548f91SRobert Mustacchi cpcgen_read_mapfile(const char *datadir, const char *platform)
42053548f91SRobert Mustacchi {
42153548f91SRobert Mustacchi 	FILE *map;
42253548f91SRobert Mustacchi 	char *mappath, *last;
42353548f91SRobert Mustacchi 	char *data = NULL;
42453548f91SRobert Mustacchi 	size_t datalen = 0;
42553548f91SRobert Mustacchi 	uint_t lineno;
42653548f91SRobert Mustacchi 
42753548f91SRobert Mustacchi 	if (asprintf(&mappath, "%s/%s", datadir, cpcgen_mapfile) == -1) {
42853548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to mapfile");
42953548f91SRobert Mustacchi 	}
43053548f91SRobert Mustacchi 
43153548f91SRobert Mustacchi 	if ((map = fopen(mappath, "r")) == NULL) {
43253548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data mapfile %s", mappath);
43353548f91SRobert Mustacchi 	}
43453548f91SRobert Mustacchi 
43553548f91SRobert Mustacchi 	lineno = 0;
43653548f91SRobert Mustacchi 	while (getline(&data, &datalen, map) != -1) {
43753548f91SRobert Mustacchi 		char *fstr, *path, *tstr;
43853548f91SRobert Mustacchi 		const char *name;
43953548f91SRobert Mustacchi 		uint_t family, model;
44053548f91SRobert Mustacchi 		cpc_type_t type;
44153548f91SRobert Mustacchi 		cpc_map_t *map;
44253548f91SRobert Mustacchi 		cpc_proc_t *proc;
44353548f91SRobert Mustacchi 
44453548f91SRobert Mustacchi 		/*
44553548f91SRobert Mustacchi 		 * The first line contains the header:
44653548f91SRobert Mustacchi 		 * Family-model,Version,Filename,EventType
44753548f91SRobert Mustacchi 		 */
44853548f91SRobert Mustacchi 		lineno++;
44953548f91SRobert Mustacchi 		if (lineno == 1) {
45053548f91SRobert Mustacchi 			continue;
45153548f91SRobert Mustacchi 		}
45253548f91SRobert Mustacchi 
45353548f91SRobert Mustacchi 		if ((fstr = strtok_r(data, ",", &last)) == NULL ||
45453548f91SRobert Mustacchi 		    strtok_r(NULL, ",", &last) == NULL ||
45553548f91SRobert Mustacchi 		    (path = strtok_r(NULL, ",", &last)) == NULL ||
45653548f91SRobert Mustacchi 		    (tstr = strtok_r(NULL, "\n", &last)) == NULL) {
45753548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse mapfile line "
45853548f91SRobert Mustacchi 			    "%u in %s", lineno, mappath);
45953548f91SRobert Mustacchi 		}
46053548f91SRobert Mustacchi 
46153548f91SRobert Mustacchi 		cpcgen_parse_model(fstr, &family, &model);
46253548f91SRobert Mustacchi 
46353548f91SRobert Mustacchi 		if (strcmp(tstr, "core") == 0) {
46453548f91SRobert Mustacchi 			type = CPC_FILE_CORE;
46553548f91SRobert Mustacchi 		} else if (strcmp(tstr, "offcore") == 0) {
46653548f91SRobert Mustacchi 			type = CPC_FILE_OFF_CORE;
46753548f91SRobert Mustacchi 		} else if (strcmp(tstr, "uncore") == 0) {
46853548f91SRobert Mustacchi 			type = CPC_FILE_UNCORE;
46953548f91SRobert Mustacchi 		} else if (strcmp(tstr, "fp_arith_inst") == 0) {
47053548f91SRobert Mustacchi 			type = CPC_FILE_FP_MATH;
47153548f91SRobert Mustacchi 		} else if (strcmp(tstr, "uncore experimental") == 0) {
47253548f91SRobert Mustacchi 			type = CPC_FILE_UNCORE_EXP;
47353548f91SRobert Mustacchi 		} else {
47453548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "unknown file type \"%s\" on line "
47553548f91SRobert Mustacchi 			    "%u", tstr, lineno);
47653548f91SRobert Mustacchi 		}
47753548f91SRobert Mustacchi 
47853548f91SRobert Mustacchi 		if ((name = cpcgen_use_arch(path, type, platform)) == NULL)
47953548f91SRobert Mustacchi 			continue;
48053548f91SRobert Mustacchi 
48153548f91SRobert Mustacchi 		if ((map = cpcgen_map_lookup(path)) == NULL) {
48253548f91SRobert Mustacchi 			nvlist_t *parsed;
48353548f91SRobert Mustacchi 
48453548f91SRobert Mustacchi 			parsed = cpcgen_read_datafile(datadir, path);
48553548f91SRobert Mustacchi 
48653548f91SRobert Mustacchi 			if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) {
48753548f91SRobert Mustacchi 				err(EXIT_FAILURE, "failed to allocate space "
48853548f91SRobert Mustacchi 				    "for cpc file");
48953548f91SRobert Mustacchi 			}
49053548f91SRobert Mustacchi 
49153548f91SRobert Mustacchi 			if ((map->cmap_path = strdup(path)) == NULL) {
49253548f91SRobert Mustacchi 				err(EXIT_FAILURE, "failed to duplicate path "
49353548f91SRobert Mustacchi 				    "string");
49453548f91SRobert Mustacchi 			}
49553548f91SRobert Mustacchi 
49653548f91SRobert Mustacchi 			map->cmap_type = type;
49753548f91SRobert Mustacchi 			map->cmap_data = parsed;
49853548f91SRobert Mustacchi 			map->cmap_next = cpcgen_maps;
49953548f91SRobert Mustacchi 			map->cmap_name = name;
50053548f91SRobert Mustacchi 			cpcgen_maps = map;
50153548f91SRobert Mustacchi 		}
50253548f91SRobert Mustacchi 
50353548f91SRobert Mustacchi 		if ((proc = malloc(sizeof (cpc_proc_t))) == NULL) {
50453548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
50553548f91SRobert Mustacchi 			    "family and model tracking");
50653548f91SRobert Mustacchi 		}
50753548f91SRobert Mustacchi 
50853548f91SRobert Mustacchi 		proc->cproc_family = family;
50953548f91SRobert Mustacchi 		proc->cproc_model = model;
51053548f91SRobert Mustacchi 		proc->cproc_next = map->cmap_procs;
51153548f91SRobert Mustacchi 		map->cmap_procs = proc;
51253548f91SRobert Mustacchi 	}
51353548f91SRobert Mustacchi 
51453548f91SRobert Mustacchi 	if (errno != 0 || ferror(map)) {
51553548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to read %s", mappath);
51653548f91SRobert Mustacchi 	}
51753548f91SRobert Mustacchi 
51853548f91SRobert Mustacchi 	if (fclose(map) == EOF) {
51953548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to close %s", mappath);
52053548f91SRobert Mustacchi 	}
52153548f91SRobert Mustacchi 	free(data);
52253548f91SRobert Mustacchi 	free(mappath);
52353548f91SRobert Mustacchi }
52453548f91SRobert Mustacchi 
52553548f91SRobert Mustacchi static char *
52653548f91SRobert Mustacchi cpcgen_manual_name(cpc_map_t *map)
52753548f91SRobert Mustacchi {
52853548f91SRobert Mustacchi 	char *name;
52953548f91SRobert Mustacchi 
53053548f91SRobert Mustacchi 	if (asprintf(&name, "%s_events.3cpc", map->cmap_name) == -1) {
53153548f91SRobert Mustacchi 		warn("failed to assemble manual page name for %s",
53253548f91SRobert Mustacchi 		    map->cmap_path);
53353548f91SRobert Mustacchi 		return (NULL);
53453548f91SRobert Mustacchi 	}
53553548f91SRobert Mustacchi 
53653548f91SRobert Mustacchi 	return (name);
53753548f91SRobert Mustacchi }
53853548f91SRobert Mustacchi 
53953548f91SRobert Mustacchi static boolean_t
54053548f91SRobert Mustacchi cpcgen_manual_file_before(FILE *f, cpc_map_t *map)
54153548f91SRobert Mustacchi {
54253548f91SRobert Mustacchi 	size_t i;
54353548f91SRobert Mustacchi 	char *upper;
54453548f91SRobert Mustacchi 	cpc_proc_t *proc;
54553548f91SRobert Mustacchi 
54653548f91SRobert Mustacchi 	if ((upper = strdup(map->cmap_name)) == NULL) {
54753548f91SRobert Mustacchi 		warn("failed to duplicate manual name for %s", map->cmap_name);
54853548f91SRobert Mustacchi 		return (B_FALSE);
54953548f91SRobert Mustacchi 	}
55053548f91SRobert Mustacchi 
55153548f91SRobert Mustacchi 	for (i = 0; upper[i] != '\0'; i++) {
55253548f91SRobert Mustacchi 		upper[i] = toupper(upper[i]);
55353548f91SRobert Mustacchi 	}
55453548f91SRobert Mustacchi 
55553548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_header, map->cmap_path, upper,
55653548f91SRobert Mustacchi 	    map->cmap_name) == -1) {
55753548f91SRobert Mustacchi 		warn("failed to write out manual header for %s",
55853548f91SRobert Mustacchi 		    map->cmap_name);
55953548f91SRobert Mustacchi 		free(upper);
56053548f91SRobert Mustacchi 		return (B_FALSE);
56153548f91SRobert Mustacchi 	}
56253548f91SRobert Mustacchi 
56353548f91SRobert Mustacchi 	for (proc = map->cmap_procs; proc != NULL; proc = proc->cproc_next) {
56453548f91SRobert Mustacchi 		if (fprintf(f, ".It\n.Sy Family 0x%x, Model 0x%x\n",
56553548f91SRobert Mustacchi 		    proc->cproc_family, proc->cproc_model) == -1) {
56653548f91SRobert Mustacchi 			warn("failed to write out model information for %s",
56753548f91SRobert Mustacchi 			    map->cmap_name);
56853548f91SRobert Mustacchi 			free(upper);
56953548f91SRobert Mustacchi 			return (B_FALSE);
57053548f91SRobert Mustacchi 		}
57153548f91SRobert Mustacchi 	}
57253548f91SRobert Mustacchi 
57353548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_data, map->cmap_path, upper,
57453548f91SRobert Mustacchi 	    map->cmap_name) == -1) {
57553548f91SRobert Mustacchi 		warn("failed to write out manual header for %s",
57653548f91SRobert Mustacchi 		    map->cmap_name);
57753548f91SRobert Mustacchi 		free(upper);
57853548f91SRobert Mustacchi 		return (B_FALSE);
57953548f91SRobert Mustacchi 	}
58053548f91SRobert Mustacchi 
58153548f91SRobert Mustacchi 	free(upper);
58253548f91SRobert Mustacchi 	return (B_TRUE);
58353548f91SRobert Mustacchi }
58453548f91SRobert Mustacchi 
58553548f91SRobert Mustacchi static boolean_t
58653548f91SRobert Mustacchi cpcgen_manual_file_after(FILE *f, cpc_map_t *map)
58753548f91SRobert Mustacchi {
58853548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_trailer) == -1) {
58953548f91SRobert Mustacchi 		warn("failed to write out manual header for %s",
59053548f91SRobert Mustacchi 		    map->cmap_name);
59153548f91SRobert Mustacchi 		return (B_FALSE);
59253548f91SRobert Mustacchi 	}
59353548f91SRobert Mustacchi 
59453548f91SRobert Mustacchi 	return (B_TRUE);
59553548f91SRobert Mustacchi }
59653548f91SRobert Mustacchi 
59753548f91SRobert Mustacchi static boolean_t
59853548f91SRobert Mustacchi cpcgen_manual_event(FILE *f, nvlist_t *nvl, const char *path, uint32_t ent)
59953548f91SRobert Mustacchi {
60053548f91SRobert Mustacchi 	char *event, *lname, *brief = NULL, *public = NULL, *errata = NULL;
60153548f91SRobert Mustacchi 	size_t i;
60253548f91SRobert Mustacchi 
60353548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
60453548f91SRobert Mustacchi 		warnx("Found event without 'EventName' property "
60553548f91SRobert Mustacchi 		    "in %s, entry %u", path, ent);
60653548f91SRobert Mustacchi 		return (B_FALSE);
60753548f91SRobert Mustacchi 	}
60853548f91SRobert Mustacchi 
60953548f91SRobert Mustacchi 	/*
61053548f91SRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
61153548f91SRobert Mustacchi 	 */
61253548f91SRobert Mustacchi 	if ((lname = strdup(event)) == NULL) {
61353548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", event);
61453548f91SRobert Mustacchi 	}
61553548f91SRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
61653548f91SRobert Mustacchi 		lname[i] = tolower(event[i]);
61753548f91SRobert Mustacchi 	}
61853548f91SRobert Mustacchi 
61953548f91SRobert Mustacchi 	/*
62053548f91SRobert Mustacchi 	 * Try to get the other event fields, but if they're not there, don't
62153548f91SRobert Mustacchi 	 * worry about it.
62253548f91SRobert Mustacchi 	 */
62353548f91SRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "BriefDescription", &brief);
62453548f91SRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "PublicDescription", &public);
62553548f91SRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "Errata", &errata);
62653548f91SRobert Mustacchi 	if (errata != NULL && (strcmp(errata, "0") == 0 ||
62753548f91SRobert Mustacchi 	    strcmp(errata, "null") == 0)) {
62853548f91SRobert Mustacchi 		errata = NULL;
62953548f91SRobert Mustacchi 	}
63053548f91SRobert Mustacchi 
63153548f91SRobert Mustacchi 	if (fprintf(f, ".It Sy %s\n", lname) == -1) {
63253548f91SRobert Mustacchi 		warn("failed to write out probe entry %s", event);
63353548f91SRobert Mustacchi 		free(lname);
63453548f91SRobert Mustacchi 		return (B_FALSE);
63553548f91SRobert Mustacchi 	}
63653548f91SRobert Mustacchi 
63753548f91SRobert Mustacchi 	if (public != NULL) {
63853548f91SRobert Mustacchi 		if (fprintf(f, "%s\n", public) == -1) {
63953548f91SRobert Mustacchi 			warn("failed to write out probe entry %s", event);
64053548f91SRobert Mustacchi 			free(lname);
64153548f91SRobert Mustacchi 			return (B_FALSE);
64253548f91SRobert Mustacchi 		}
64353548f91SRobert Mustacchi 	} else if (brief != NULL) {
64453548f91SRobert Mustacchi 		if (fprintf(f, "%s\n", brief) == -1) {
64553548f91SRobert Mustacchi 			warn("failed to write out probe entry %s", event);
64653548f91SRobert Mustacchi 			free(lname);
64753548f91SRobert Mustacchi 			return (B_FALSE);
64853548f91SRobert Mustacchi 		}
64953548f91SRobert Mustacchi 	}
65053548f91SRobert Mustacchi 
65153548f91SRobert Mustacchi 	if (errata != NULL) {
65253548f91SRobert Mustacchi 		if (fprintf(f, ".Pp\nThe following errata may apply to this: "
65353548f91SRobert Mustacchi 		    "%s\n", errata) == -1) {
65453548f91SRobert Mustacchi 
65553548f91SRobert Mustacchi 			warn("failed to write out probe entry %s", event);
65653548f91SRobert Mustacchi 			free(lname);
65753548f91SRobert Mustacchi 			return (B_FALSE);
65853548f91SRobert Mustacchi 		}
65953548f91SRobert Mustacchi 	}
66053548f91SRobert Mustacchi 
66153548f91SRobert Mustacchi 	free(lname);
66253548f91SRobert Mustacchi 	return (B_TRUE);
66353548f91SRobert Mustacchi }
66453548f91SRobert Mustacchi 
66553548f91SRobert Mustacchi static char *
66653548f91SRobert Mustacchi cpcgen_cfile_name(cpc_map_t *map)
66753548f91SRobert Mustacchi {
66853548f91SRobert Mustacchi 	char *name;
66953548f91SRobert Mustacchi 
67053548f91SRobert Mustacchi 	if (asprintf(&name, "core_pcbe_%s.c", map->cmap_name) == -1) {
67153548f91SRobert Mustacchi 		warn("failed to assemble file name for %s", map->cmap_path);
67253548f91SRobert Mustacchi 		return (NULL);
67353548f91SRobert Mustacchi 	}
67453548f91SRobert Mustacchi 
67553548f91SRobert Mustacchi 	return (name);
67653548f91SRobert Mustacchi }
67753548f91SRobert Mustacchi 
67853548f91SRobert Mustacchi static boolean_t
67953548f91SRobert Mustacchi cpcgen_cfile_file_before(FILE *f, cpc_map_t *map)
68053548f91SRobert Mustacchi {
68153548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, map->cmap_path) == -1) {
68253548f91SRobert Mustacchi 		warn("failed to write header to temporary file for %s",
68353548f91SRobert Mustacchi 		    map->cmap_path);
68453548f91SRobert Mustacchi 		return (B_FALSE);
68553548f91SRobert Mustacchi 	}
68653548f91SRobert Mustacchi 
68753548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_table_start, map->cmap_name) == -1) {
68853548f91SRobert Mustacchi 		warn("failed to write header to temporary file for %s",
68953548f91SRobert Mustacchi 		    map->cmap_path);
69053548f91SRobert Mustacchi 		return (B_FALSE);
69153548f91SRobert Mustacchi 	}
69253548f91SRobert Mustacchi 
69353548f91SRobert Mustacchi 	return (B_TRUE);
69453548f91SRobert Mustacchi }
69553548f91SRobert Mustacchi 
69653548f91SRobert Mustacchi static boolean_t
69753548f91SRobert Mustacchi cpcgen_cfile_file_after(FILE *f, cpc_map_t *map)
69853548f91SRobert Mustacchi {
69953548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_table_end) == -1) {
70053548f91SRobert Mustacchi 		warn("failed to write footer to temporary file for %s",
70153548f91SRobert Mustacchi 		    map->cmap_path);
70253548f91SRobert Mustacchi 		return (B_FALSE);
70353548f91SRobert Mustacchi 	}
70453548f91SRobert Mustacchi 
70553548f91SRobert Mustacchi 	return (B_TRUE);
70653548f91SRobert Mustacchi }
70753548f91SRobert Mustacchi 
70853548f91SRobert Mustacchi static boolean_t
70953548f91SRobert Mustacchi cpcgen_cfile_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent)
71053548f91SRobert Mustacchi {
71153548f91SRobert Mustacchi 	char *ecode, *umask, *name, *counter, *lname, *cmask;
71253548f91SRobert Mustacchi 	size_t i;
71353548f91SRobert Mustacchi 
71453548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &name) != 0) {
71553548f91SRobert Mustacchi 		warnx("Found event without 'EventName' property "
71653548f91SRobert Mustacchi 		    "in %s, entry %u", path, ent);
71753548f91SRobert Mustacchi 		return (B_FALSE);
71853548f91SRobert Mustacchi 	}
71953548f91SRobert Mustacchi 
72053548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
72153548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
72253548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0) {
72353548f91SRobert Mustacchi 		warnx("event %s (index %u) from %s, missing "
72453548f91SRobert Mustacchi 		    "required properties for C file translation",
72553548f91SRobert Mustacchi 		    name, ent, path);
72653548f91SRobert Mustacchi 		return (B_FALSE);
72753548f91SRobert Mustacchi 	}
72853548f91SRobert Mustacchi 
72953548f91SRobert Mustacchi 	/*
73053548f91SRobert Mustacchi 	 * While we could try and parse the counters manually, just do this the
73153548f91SRobert Mustacchi 	 * max power way for now based on all possible values.
73253548f91SRobert Mustacchi 	 */
73353548f91SRobert Mustacchi 	if (strcmp(counter, "0") == 0 || strcmp(counter, "0,") == 0) {
73453548f91SRobert Mustacchi 		cmask = "C0";
73553548f91SRobert Mustacchi 	} else if (strcmp(counter, "1") == 0) {
73653548f91SRobert Mustacchi 		cmask = "C1";
73753548f91SRobert Mustacchi 	} else if (strcmp(counter, "2") == 0) {
73853548f91SRobert Mustacchi 		cmask = "C2";
73953548f91SRobert Mustacchi 	} else if (strcmp(counter, "3") == 0) {
74053548f91SRobert Mustacchi 		cmask = "C3";
74153548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,1") == 0) {
74253548f91SRobert Mustacchi 		cmask = "C0|C1";
74353548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,1,2") == 0) {
74453548f91SRobert Mustacchi 		cmask = "C0|C1|C2";
74553548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,1,2,3") == 0) {
74653548f91SRobert Mustacchi 		cmask = "C0|C1|C2|C3";
74753548f91SRobert Mustacchi 	} else if (strcmp(counter, "0,2,3") == 0) {
74853548f91SRobert Mustacchi 		cmask = "C0|C2|C3";
74953548f91SRobert Mustacchi 	} else if (strcmp(counter, "1,2,3") == 0) {
75053548f91SRobert Mustacchi 		cmask = "C1|C2|C3";
75153548f91SRobert Mustacchi 	} else if (strcmp(counter, "2,3") == 0) {
75253548f91SRobert Mustacchi 		cmask = "C2|C3";
75353548f91SRobert Mustacchi 	} else {
75453548f91SRobert Mustacchi 		warnx("event %s (index %u) from %s, has unknown "
75553548f91SRobert Mustacchi 		    "counter value \"%s\"", name, ent, path, counter);
75653548f91SRobert Mustacchi 		return (B_FALSE);
75753548f91SRobert Mustacchi 	}
75853548f91SRobert Mustacchi 
75953548f91SRobert Mustacchi 
76053548f91SRobert Mustacchi 	/*
76153548f91SRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
76253548f91SRobert Mustacchi 	 */
76353548f91SRobert Mustacchi 	if ((lname = strdup(name)) == NULL) {
76453548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", name);
76553548f91SRobert Mustacchi 	}
76653548f91SRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
76753548f91SRobert Mustacchi 		lname[i] = tolower(name[i]);
76853548f91SRobert Mustacchi 	}
76953548f91SRobert Mustacchi 
77053548f91SRobert Mustacchi 	if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, cmask,
77153548f91SRobert Mustacchi 	    lname) == -1) {
77253548f91SRobert Mustacchi 		warn("failed to write out entry %s from %s", name, path);
77353548f91SRobert Mustacchi 		free(lname);
77453548f91SRobert Mustacchi 		return (B_FALSE);
77553548f91SRobert Mustacchi 	}
77653548f91SRobert Mustacchi 
77753548f91SRobert Mustacchi 	free(lname);
77853548f91SRobert Mustacchi 
77953548f91SRobert Mustacchi 	/*
78053548f91SRobert Mustacchi 	 * Check if we have any PAPI aliases.
78153548f91SRobert Mustacchi 	 */
78253548f91SRobert Mustacchi 	for (i = 0; cpcgen_papi_map[i].cpapi_intc != NULL; i++) {
78353548f91SRobert Mustacchi 		if (strcmp(name, cpcgen_papi_map[i].cpapi_intc) != 0)
78453548f91SRobert Mustacchi 			continue;
78553548f91SRobert Mustacchi 
78653548f91SRobert Mustacchi 		if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask,
78753548f91SRobert Mustacchi 		    cmask, cpcgen_papi_map[i].cpapi_papi) == -1) {
78853548f91SRobert Mustacchi 			warn("failed to write out entry %s from %s", name,
78953548f91SRobert Mustacchi 			    path);
79053548f91SRobert Mustacchi 			return (B_FALSE);
79153548f91SRobert Mustacchi 		}
79253548f91SRobert Mustacchi 	}
79353548f91SRobert Mustacchi 
79453548f91SRobert Mustacchi 	return (B_TRUE);
79553548f91SRobert Mustacchi }
79653548f91SRobert Mustacchi 
79753548f91SRobert Mustacchi /*
79853548f91SRobert Mustacchi  * Generate a header file that declares all of these arrays and provide a map
79953548f91SRobert Mustacchi  * for models to the corresponding table to use.
80053548f91SRobert Mustacchi  */
80153548f91SRobert Mustacchi static void
80253548f91SRobert Mustacchi cpcgen_common_files(int dirfd)
80353548f91SRobert Mustacchi {
80453548f91SRobert Mustacchi 	const char *fname = "core_pcbe_cpcgen.h";
80553548f91SRobert Mustacchi 	char *tmpname;
80653548f91SRobert Mustacchi 	int fd;
80753548f91SRobert Mustacchi 	FILE *f;
80853548f91SRobert Mustacchi 	cpc_map_t *map;
80953548f91SRobert Mustacchi 
81053548f91SRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
81153548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
81253548f91SRobert Mustacchi 	}
81353548f91SRobert Mustacchi 
81453548f91SRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
81553548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
81653548f91SRobert Mustacchi 		    tmpname);
81753548f91SRobert Mustacchi 	}
81853548f91SRobert Mustacchi 
81953548f91SRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
82053548f91SRobert Mustacchi 		int e = errno;
82153548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
82253548f91SRobert Mustacchi 		errno = e;
82353548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
82453548f91SRobert Mustacchi 	}
82553548f91SRobert Mustacchi 
82653548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) {
82753548f91SRobert Mustacchi 		int e = errno;
82853548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
82953548f91SRobert Mustacchi 		errno = e;
83053548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
83153548f91SRobert Mustacchi 		    "for %s", fname);
83253548f91SRobert Mustacchi 	}
83353548f91SRobert Mustacchi 
83453548f91SRobert Mustacchi 	if (fprintf(f, "#ifndef _CORE_PCBE_CPCGEN_H\n"
83553548f91SRobert Mustacchi 	    "#define\t_CORE_PCBE_CPCGEN_H\n"
83653548f91SRobert Mustacchi 	    "\n"
83753548f91SRobert Mustacchi 	    "#ifdef __cplusplus\n"
83853548f91SRobert Mustacchi 	    "extern \"C\" {\n"
83953548f91SRobert Mustacchi 	    "#endif\n"
84053548f91SRobert Mustacchi 	    "\n"
84153548f91SRobert Mustacchi 	    "extern const struct events_table_t *core_cpcgen_table(uint_t);\n"
84253548f91SRobert Mustacchi 	    "\n") == -1) {
84353548f91SRobert Mustacchi 		int e = errno;
84453548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
84553548f91SRobert Mustacchi 		errno = e;
84653548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
84753548f91SRobert Mustacchi 		    "temporary file for %s", fname);
84853548f91SRobert Mustacchi 	}
84953548f91SRobert Mustacchi 
85053548f91SRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
85153548f91SRobert Mustacchi 		if (fprintf(f, "extern const struct events_table_t "
85253548f91SRobert Mustacchi 		    "pcbe_core_events_%s[];\n", map->cmap_name) == -1) {
85353548f91SRobert Mustacchi 			int e = errno;
85453548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
85553548f91SRobert Mustacchi 			errno = e;
85653548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write entry to "
85753548f91SRobert Mustacchi 			    "temporary file for %s", fname);
85853548f91SRobert Mustacchi 		}
85953548f91SRobert Mustacchi 	}
86053548f91SRobert Mustacchi 
86153548f91SRobert Mustacchi 	if (fprintf(f, "\n"
86253548f91SRobert Mustacchi 	    "#ifdef __cplusplus\n"
86353548f91SRobert Mustacchi 	    "}\n"
86453548f91SRobert Mustacchi 	    "#endif\n"
86553548f91SRobert Mustacchi 	    "\n"
86653548f91SRobert Mustacchi 	    "#endif /* _CORE_PCBE_CPCGEN_H */\n") == -1) {
86753548f91SRobert Mustacchi 		int e = errno;
86853548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
86953548f91SRobert Mustacchi 		errno = e;
87053548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
87153548f91SRobert Mustacchi 		    "temporary file for %s", fname);
87253548f91SRobert Mustacchi 	}
87353548f91SRobert Mustacchi 
87453548f91SRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
87553548f91SRobert Mustacchi 		int e = errno;
87653548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
87753548f91SRobert Mustacchi 		errno = e;
87853548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
87953548f91SRobert Mustacchi 	}
88053548f91SRobert Mustacchi 
88153548f91SRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
88253548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
88353548f91SRobert Mustacchi 		    tmpname);
88453548f91SRobert Mustacchi 	}
88553548f91SRobert Mustacchi 
88653548f91SRobert Mustacchi 	free(tmpname);
88753548f91SRobert Mustacchi 
88853548f91SRobert Mustacchi 	/* Now again for the .c file. */
88953548f91SRobert Mustacchi 	fname = "core_pcbe_cpcgen.c";
89053548f91SRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
89153548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
89253548f91SRobert Mustacchi 	}
89353548f91SRobert Mustacchi 
89453548f91SRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
89553548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
89653548f91SRobert Mustacchi 		    tmpname);
89753548f91SRobert Mustacchi 	}
89853548f91SRobert Mustacchi 
89953548f91SRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
90053548f91SRobert Mustacchi 		int e = errno;
90153548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
90253548f91SRobert Mustacchi 		errno = e;
90353548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
90453548f91SRobert Mustacchi 	}
90553548f91SRobert Mustacchi 
90653548f91SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_header, cpcgen_mapfile) == -1) {
90753548f91SRobert Mustacchi 		int e = errno;
90853548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
90953548f91SRobert Mustacchi 		errno = e;
91053548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
91153548f91SRobert Mustacchi 		    "for %s", fname);
91253548f91SRobert Mustacchi 	}
91353548f91SRobert Mustacchi 
91453548f91SRobert Mustacchi 	if (fprintf(f, "#include <core_pcbe_table.h>\n"
91553548f91SRobert Mustacchi 	    "#include <sys/null.h>\n"
91653548f91SRobert Mustacchi 	    "#include \"core_pcbe_cpcgen.h\"\n"
91753548f91SRobert Mustacchi 	    "\n"
91853548f91SRobert Mustacchi 	    "const struct events_table_t *\n"
91953548f91SRobert Mustacchi 	    "core_cpcgen_table(uint_t model)\n"
92053548f91SRobert Mustacchi 	    "{\n"
92153548f91SRobert Mustacchi 	    "\tswitch (model) {\n") == -1) {
92253548f91SRobert Mustacchi 		int e = errno;
92353548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
92453548f91SRobert Mustacchi 		errno = e;
92553548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
92653548f91SRobert Mustacchi 		    "temporary file for %s", fname);
92753548f91SRobert Mustacchi 	}
92853548f91SRobert Mustacchi 
92953548f91SRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
93053548f91SRobert Mustacchi 		cpc_proc_t *p;
93153548f91SRobert Mustacchi 		for (p = map->cmap_procs; p != NULL; p = p->cproc_next) {
93253548f91SRobert Mustacchi 			assert(p->cproc_family == 6);
93353548f91SRobert Mustacchi 			if (fprintf(f, "\t\tcase 0x%x:\n", p->cproc_model) ==
93453548f91SRobert Mustacchi 			    -1) {
93553548f91SRobert Mustacchi 				int e = errno;
93653548f91SRobert Mustacchi 				(void) unlinkat(dirfd, tmpname, 0);
93753548f91SRobert Mustacchi 				errno = e;
93853548f91SRobert Mustacchi 				errx(EXIT_FAILURE, "failed to write header to "
93953548f91SRobert Mustacchi 				    "temporary file for %s", fname);
94053548f91SRobert Mustacchi 			}
94153548f91SRobert Mustacchi 		}
94253548f91SRobert Mustacchi 		if (fprintf(f, "\t\t\treturn (pcbe_core_events_%s);\n",
94353548f91SRobert Mustacchi 		    map->cmap_name) == -1) {
94453548f91SRobert Mustacchi 			int e = errno;
94553548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
94653548f91SRobert Mustacchi 			errno = e;
94753548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write entry to "
94853548f91SRobert Mustacchi 			    "temporary file for %s", fname);
94953548f91SRobert Mustacchi 		}
95053548f91SRobert Mustacchi 	}
95153548f91SRobert Mustacchi 
95253548f91SRobert Mustacchi 	if (fprintf(f, "\t\tdefault:\n"
95353548f91SRobert Mustacchi 	    "\t\t\treturn (NULL);\n"
95453548f91SRobert Mustacchi 	    "\t}\n"
95553548f91SRobert Mustacchi 	    "}\n") == -1) {
95653548f91SRobert Mustacchi 		int e = errno;
95753548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
95853548f91SRobert Mustacchi 		errno = e;
95953548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
96053548f91SRobert Mustacchi 		    "temporary file for %s", fname);
96153548f91SRobert Mustacchi 	}
96253548f91SRobert Mustacchi 
96353548f91SRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
96453548f91SRobert Mustacchi 		int e = errno;
96553548f91SRobert Mustacchi 		(void) unlinkat(dirfd, tmpname, 0);
96653548f91SRobert Mustacchi 		errno = e;
96753548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
96853548f91SRobert Mustacchi 	}
96953548f91SRobert Mustacchi 
97053548f91SRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
97153548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
97253548f91SRobert Mustacchi 		    tmpname);
97353548f91SRobert Mustacchi 	}
97453548f91SRobert Mustacchi 
97553548f91SRobert Mustacchi 	free(tmpname);
97653548f91SRobert Mustacchi }
97753548f91SRobert Mustacchi 
97853548f91SRobert Mustacchi /*
97953548f91SRobert Mustacchi  * Look at a rule to determine whether or not we should consider including it or
98053548f91SRobert Mustacchi  * not. At this point we've already filtered things such that we only get core
98153548f91SRobert Mustacchi  * events.
98253548f91SRobert Mustacchi  *
98353548f91SRobert Mustacchi  * To consider an entry, we currently apply the following criteria:
98453548f91SRobert Mustacchi  *
98553548f91SRobert Mustacchi  * - The MSRIndex and MSRValue are zero. Programming additional MSRs is no
98653548f91SRobert Mustacchi  *   supported right now.
98753548f91SRobert Mustacchi  * - TakenAlone is non-zero, which means that it cannot run at the same time as
98853548f91SRobert Mustacchi  *   another field.
98953548f91SRobert Mustacchi  * - Offcore is one, indicating that it is off the core and we need to figure
99053548f91SRobert Mustacchi  *   out if we can support this.
99153548f91SRobert Mustacchi  * - If the counter is fixed, don't use it for now.
99253548f91SRobert Mustacchi  * - If more than one value is specified in the EventCode or UMask values
99353548f91SRobert Mustacchi  */
99453548f91SRobert Mustacchi static boolean_t
99553548f91SRobert Mustacchi cpcgen_skip_entry(nvlist_t *nvl, const char *path, uint_t ent)
99653548f91SRobert Mustacchi {
99753548f91SRobert Mustacchi 	char *event, *msridx, *msrval, *taken, *offcore, *counter;
99853548f91SRobert Mustacchi 	char *ecode, *umask;
99953548f91SRobert Mustacchi 
100053548f91SRobert Mustacchi 	/*
100153548f91SRobert Mustacchi 	 * Require EventName, it's kind of useless without that.
100253548f91SRobert Mustacchi 	 */
100353548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
100453548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "Found event without 'EventName' property "
100553548f91SRobert Mustacchi 		    "in %s, entry %u", path, ent);
100653548f91SRobert Mustacchi 	}
100753548f91SRobert Mustacchi 
100853548f91SRobert Mustacchi 	/*
100953548f91SRobert Mustacchi 	 * If we can't find an expected value, whine about it.
101053548f91SRobert Mustacchi 	 */
101153548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "MSRIndex", &msridx) != 0 ||
101253548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "MSRValue", &msrval) != 0 ||
101353548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0 ||
101453548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
101553548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
101653548f91SRobert Mustacchi 	    nvlist_lookup_string(nvl, "Offcore", &offcore) != 0) {
101753548f91SRobert Mustacchi 		warnx("Skipping event %s (index %u) from %s, missing required "
101853548f91SRobert Mustacchi 		    "property", event, ent, path);
101953548f91SRobert Mustacchi 		return (B_TRUE);
102053548f91SRobert Mustacchi 	}
102153548f91SRobert Mustacchi 
102253548f91SRobert Mustacchi 	/*
102353548f91SRobert Mustacchi 	 * MSRIndex and MSRvalue comes as either "0" or "0x00".
102453548f91SRobert Mustacchi 	 */
102553548f91SRobert Mustacchi 	if ((strcmp(msridx, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
102653548f91SRobert Mustacchi 	    (strcmp(msrval, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
102753548f91SRobert Mustacchi 	    strcmp(offcore, "0") != 0 || strchr(ecode, ',') != NULL ||
102853548f91SRobert Mustacchi 	    strchr(umask, ',') != NULL) {
102953548f91SRobert Mustacchi 		return (B_TRUE);
103053548f91SRobert Mustacchi 	}
103153548f91SRobert Mustacchi 
103253548f91SRobert Mustacchi 	/*
103353548f91SRobert Mustacchi 	 * Unfortunately, not everything actually has "TakenAlone". If it
103453548f91SRobert Mustacchi 	 * doesn't, we assume that it doesn't have to be.
103553548f91SRobert Mustacchi 	 */
103653548f91SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "TakenAlone", &taken) == 0 &&
103753548f91SRobert Mustacchi 	    strcmp(taken, "0") != 0) {
103853548f91SRobert Mustacchi 		return (B_TRUE);
103953548f91SRobert Mustacchi 	}
104053548f91SRobert Mustacchi 
104153548f91SRobert Mustacchi 
104253548f91SRobert Mustacchi 	if (strncasecmp(counter, "fixed", strlen("fixed")) == 0)
104353548f91SRobert Mustacchi 		return (B_TRUE);
104453548f91SRobert Mustacchi 
104553548f91SRobert Mustacchi 	return (B_FALSE);
104653548f91SRobert Mustacchi }
104753548f91SRobert Mustacchi 
104853548f91SRobert Mustacchi /*
104953548f91SRobert Mustacchi  * For each processor family, generate a data file that contains all of the
105053548f91SRobert Mustacchi  * events that we support. Also generate a header that can be included that
105153548f91SRobert Mustacchi  * declares all of the tables.
105253548f91SRobert Mustacchi  */
105353548f91SRobert Mustacchi static void
105453548f91SRobert Mustacchi cpcgen_gen(int dirfd)
105553548f91SRobert Mustacchi {
105653548f91SRobert Mustacchi 	cpc_map_t *map = cpcgen_maps;
105753548f91SRobert Mustacchi 
105853548f91SRobert Mustacchi 	if (map == NULL) {
105953548f91SRobert Mustacchi 		errx(EXIT_FAILURE, "no platforms found or matched");
106053548f91SRobert Mustacchi 	}
106153548f91SRobert Mustacchi 
106253548f91SRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
106353548f91SRobert Mustacchi 		int fd, ret;
106453548f91SRobert Mustacchi 		FILE *f;
106553548f91SRobert Mustacchi 		char *tmpname, *name;
106653548f91SRobert Mustacchi 		uint32_t length, i;
106753548f91SRobert Mustacchi 
106853548f91SRobert Mustacchi 		if ((name = cpcgen_ops.cgen_op_name(map)) == NULL) {
106953548f91SRobert Mustacchi 			exit(EXIT_FAILURE);
107053548f91SRobert Mustacchi 		}
107153548f91SRobert Mustacchi 
107253548f91SRobert Mustacchi 		if (asprintf(&tmpname, ".%s.%d", name, getpid()) == -1) {
107353548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to construct temporary file "
107453548f91SRobert Mustacchi 			    "name");
107553548f91SRobert Mustacchi 		}
107653548f91SRobert Mustacchi 
107753548f91SRobert Mustacchi 		if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0444)) < 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 (!cpcgen_ops.cgen_op_file_before(f, map)) {
109053548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
109153548f91SRobert Mustacchi 			exit(EXIT_FAILURE);
109253548f91SRobert Mustacchi 		}
109353548f91SRobert Mustacchi 
109453548f91SRobert Mustacchi 		/*
109553548f91SRobert Mustacchi 		 * Iterate over array contents.
109653548f91SRobert Mustacchi 		 */
109753548f91SRobert Mustacchi 		if ((ret = nvlist_lookup_uint32(map->cmap_data, "length",
109853548f91SRobert Mustacchi 		    &length)) != 0) {
109953548f91SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to look up length property "
110053548f91SRobert Mustacchi 			    "in parsed data for %s: %s", map->cmap_path,
110153548f91SRobert Mustacchi 			    strerror(ret));
110253548f91SRobert Mustacchi 		}
110353548f91SRobert Mustacchi 
110453548f91SRobert Mustacchi 		for (i = 0; i < length; i++) {
110553548f91SRobert Mustacchi 			nvlist_t *nvl;
110653548f91SRobert Mustacchi 			char num[64];
110753548f91SRobert Mustacchi 
110853548f91SRobert Mustacchi 			(void) snprintf(num, sizeof (num), "%u", i);
110953548f91SRobert Mustacchi 			if ((ret = nvlist_lookup_nvlist(map->cmap_data,
111053548f91SRobert Mustacchi 			    num, &nvl)) != 0) {
111153548f91SRobert Mustacchi 				errx(EXIT_FAILURE, "failed to look up array "
111253548f91SRobert Mustacchi 				    "entry %u in parsed data for %s: %s", i,
111353548f91SRobert Mustacchi 				    map->cmap_path, strerror(ret));
111453548f91SRobert Mustacchi 			}
111553548f91SRobert Mustacchi 
111653548f91SRobert Mustacchi 			if (cpcgen_skip_entry(nvl, map->cmap_path, i))
111753548f91SRobert Mustacchi 				continue;
111853548f91SRobert Mustacchi 
111953548f91SRobert Mustacchi 			if (!cpcgen_ops.cgen_op_event(f, nvl, map->cmap_path,
112053548f91SRobert Mustacchi 			    i)) {
112153548f91SRobert Mustacchi 				(void) unlinkat(dirfd, tmpname, 0);
112253548f91SRobert Mustacchi 				exit(EXIT_FAILURE);
112353548f91SRobert Mustacchi 			}
112453548f91SRobert Mustacchi 		}
112553548f91SRobert Mustacchi 
112653548f91SRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_after(f, map)) {
112753548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
112853548f91SRobert Mustacchi 			exit(EXIT_FAILURE);
112953548f91SRobert Mustacchi 		}
113053548f91SRobert Mustacchi 
113153548f91SRobert Mustacchi 		if (fflush(f) != 0 || fclose(f) != 0) {
113253548f91SRobert Mustacchi 			int e = errno;
113353548f91SRobert Mustacchi 			(void) unlinkat(dirfd, tmpname, 0);
113453548f91SRobert Mustacchi 			errno = e;
113553548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to flush and close "
113653548f91SRobert Mustacchi 			    "temporary file");
113753548f91SRobert Mustacchi 		}
113853548f91SRobert Mustacchi 
113953548f91SRobert Mustacchi 		if (renameat(dirfd, tmpname, dirfd, name) != 0) {
114053548f91SRobert Mustacchi 			err(EXIT_FAILURE, "failed to rename temporary file %s",
114153548f91SRobert Mustacchi 			    tmpname);
114253548f91SRobert Mustacchi 		}
114353548f91SRobert Mustacchi 
114453548f91SRobert Mustacchi 		free(name);
114553548f91SRobert Mustacchi 		free(tmpname);
114653548f91SRobert Mustacchi 	}
114753548f91SRobert Mustacchi }
114853548f91SRobert Mustacchi 
114953548f91SRobert Mustacchi static void
115053548f91SRobert Mustacchi cpcgen_usage(const char *fmt, ...)
115153548f91SRobert Mustacchi {
115253548f91SRobert Mustacchi 	if (fmt != NULL) {
115353548f91SRobert Mustacchi 		va_list ap;
115453548f91SRobert Mustacchi 
115553548f91SRobert Mustacchi 		(void) fprintf(stderr, "%s: ", cpcgen_progname);
115653548f91SRobert Mustacchi 		va_start(ap, fmt);
115753548f91SRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
115853548f91SRobert Mustacchi 		va_end(ap);
115953548f91SRobert Mustacchi 	}
116053548f91SRobert Mustacchi 
116153548f91SRobert Mustacchi 	(void) fprintf(stderr, "Usage: %s -a|-p platform -c|-H|-m -d datadir "
116253548f91SRobert Mustacchi 	    "-o outdir\n"
116353548f91SRobert Mustacchi 	    "\n"
116453548f91SRobert Mustacchi 	    "\t-a  generate data for all platforms\n"
116553548f91SRobert Mustacchi 	    "\t-c  generate C file for CPC\n"
116653548f91SRobert Mustacchi 	    "\t-d  specify the directory containt perfmon data\n"
116753548f91SRobert Mustacchi 	    "\t-h  generate header file and common files\n"
116853548f91SRobert Mustacchi 	    "\t-m  generate manual pages for CPC data\n"
116953548f91SRobert Mustacchi 	    "\t-o  outut files in directory outdir\n"
117053548f91SRobert Mustacchi 	    "\t-p  generate data for a specified platform\n",
117153548f91SRobert Mustacchi 	    cpcgen_progname);
117253548f91SRobert Mustacchi }
117353548f91SRobert Mustacchi 
117453548f91SRobert Mustacchi int
117553548f91SRobert Mustacchi main(int argc, char *argv[])
117653548f91SRobert Mustacchi {
117753548f91SRobert Mustacchi 	int c, outdirfd;
117853548f91SRobert Mustacchi 	boolean_t do_mpage = B_FALSE, do_cfile = B_FALSE, do_header = B_FALSE,
117953548f91SRobert Mustacchi 	    do_all = B_FALSE;
118053548f91SRobert Mustacchi 	const char *datadir = NULL, *outdir = NULL, *platform = NULL;
118153548f91SRobert Mustacchi 	uint_t count = 0;
118253548f91SRobert Mustacchi 
118353548f91SRobert Mustacchi 	cpcgen_progname = basename(argv[0]);
118453548f91SRobert Mustacchi 
118553548f91SRobert Mustacchi 	while ((c = getopt(argc, argv, ":acd:hHmo:p:")) != -1) {
118653548f91SRobert Mustacchi 		switch (c) {
118753548f91SRobert Mustacchi 		case 'a':
118853548f91SRobert Mustacchi 			do_all = B_TRUE;
118953548f91SRobert Mustacchi 			break;
119053548f91SRobert Mustacchi 		case 'c':
119153548f91SRobert Mustacchi 			do_cfile = B_TRUE;
119253548f91SRobert Mustacchi 			break;
119353548f91SRobert Mustacchi 		case 'd':
119453548f91SRobert Mustacchi 			datadir = optarg;
119553548f91SRobert Mustacchi 			break;
119653548f91SRobert Mustacchi 		case 'm':
119753548f91SRobert Mustacchi 			do_mpage = B_TRUE;
119853548f91SRobert Mustacchi 			break;
119953548f91SRobert Mustacchi 		case 'H':
120053548f91SRobert Mustacchi 			do_header = B_TRUE;
120153548f91SRobert Mustacchi 			break;
120253548f91SRobert Mustacchi 		case 'o':
120353548f91SRobert Mustacchi 			outdir = optarg;
120453548f91SRobert Mustacchi 			break;
120553548f91SRobert Mustacchi 		case 'p':
120653548f91SRobert Mustacchi 			platform = optarg;
120753548f91SRobert Mustacchi 			break;
120853548f91SRobert Mustacchi 		case ':':
120953548f91SRobert Mustacchi 			cpcgen_usage("Option -%c requires an operand\n",
121053548f91SRobert Mustacchi 			    optopt);
121153548f91SRobert Mustacchi 			return (2);
121253548f91SRobert Mustacchi 		case '?':
121353548f91SRobert Mustacchi 			cpcgen_usage("Unknown option: -%c\n", optopt);
121453548f91SRobert Mustacchi 			return (2);
121553548f91SRobert Mustacchi 		case 'h':
121653548f91SRobert Mustacchi 		default:
121753548f91SRobert Mustacchi 			cpcgen_usage(NULL);
121853548f91SRobert Mustacchi 			return (2);
121953548f91SRobert Mustacchi 		}
122053548f91SRobert Mustacchi 	}
122153548f91SRobert Mustacchi 
122253548f91SRobert Mustacchi 	count = 0;
122353548f91SRobert Mustacchi 	if (do_mpage)
122453548f91SRobert Mustacchi 		count++;
122553548f91SRobert Mustacchi 	if (do_cfile)
122653548f91SRobert Mustacchi 		count++;
122753548f91SRobert Mustacchi 	if (do_header)
122853548f91SRobert Mustacchi 		count++;
122953548f91SRobert Mustacchi 	if (count > 1) {
123053548f91SRobert Mustacchi 		cpcgen_usage("Only one of -c, -h, and -m may be specified\n");
123153548f91SRobert Mustacchi 		return (2);
123253548f91SRobert Mustacchi 	} else if (count == 0) {
123353548f91SRobert Mustacchi 		cpcgen_usage("One of -c, -h, and -m is required\n");
123453548f91SRobert Mustacchi 		return (2);
123553548f91SRobert Mustacchi 	}
123653548f91SRobert Mustacchi 
123753548f91SRobert Mustacchi 	count = 0;
123853548f91SRobert Mustacchi 	if (do_all)
123953548f91SRobert Mustacchi 		count++;
124053548f91SRobert Mustacchi 	if (platform != NULL)
124153548f91SRobert Mustacchi 		count++;
124253548f91SRobert Mustacchi 	if (count > 1) {
124353548f91SRobert Mustacchi 		cpcgen_usage("Only one of -a and -p may be specified\n");
124453548f91SRobert Mustacchi 		return (2);
124553548f91SRobert Mustacchi 	} else if (count == 0) {
124653548f91SRobert Mustacchi 		cpcgen_usage("One of -a and -p is required\n");
124753548f91SRobert Mustacchi 		return (2);
124853548f91SRobert Mustacchi 	}
124953548f91SRobert Mustacchi 
125053548f91SRobert Mustacchi 
125153548f91SRobert Mustacchi 	if (outdir == NULL) {
125253548f91SRobert Mustacchi 		cpcgen_usage("Missing required output directory (-o)\n");
125353548f91SRobert Mustacchi 		return (2);
125453548f91SRobert Mustacchi 	}
125553548f91SRobert Mustacchi 
125653548f91SRobert Mustacchi 	if ((outdirfd = open(outdir, O_RDONLY)) < 0) {
125753548f91SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open output directory %s", outdir);
125853548f91SRobert Mustacchi 	}
125953548f91SRobert Mustacchi 
126053548f91SRobert Mustacchi 	if (datadir == NULL) {
126153548f91SRobert Mustacchi 		cpcgen_usage("Missing required data directory (-d)\n");
126253548f91SRobert Mustacchi 		return (2);
126353548f91SRobert Mustacchi 	}
126453548f91SRobert Mustacchi 
126553548f91SRobert Mustacchi 	cpcgen_read_mapfile(datadir, platform);
126653548f91SRobert Mustacchi 
126753548f91SRobert Mustacchi 	if (do_header) {
126853548f91SRobert Mustacchi 		cpcgen_common_files(outdirfd);
126953548f91SRobert Mustacchi 		return (0);
127053548f91SRobert Mustacchi 	}
127153548f91SRobert Mustacchi 
127253548f91SRobert Mustacchi 	if (do_mpage) {
127353548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_name = cpcgen_manual_name;
127453548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_before = cpcgen_manual_file_before;
127553548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_after = cpcgen_manual_file_after;
127653548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_event = cpcgen_manual_event;
127753548f91SRobert Mustacchi 	}
127853548f91SRobert Mustacchi 
127953548f91SRobert Mustacchi 	if (do_cfile) {
128053548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_name = cpcgen_cfile_name;
128153548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_before = cpcgen_cfile_file_before;
128253548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_file_after = cpcgen_cfile_file_after;
128353548f91SRobert Mustacchi 		cpcgen_ops.cgen_op_event = cpcgen_cfile_event;
128453548f91SRobert Mustacchi 	}
128553548f91SRobert Mustacchi 
128653548f91SRobert Mustacchi 
128753548f91SRobert Mustacchi 	cpcgen_gen(outdirfd);
128853548f91SRobert Mustacchi 
128953548f91SRobert Mustacchi 	return (0);
129053548f91SRobert Mustacchi }
1291