cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

synth_event_gen_test.c (13983B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Test module for in-kernel synthetic event creation and generation.
      4 *
      5 * Copyright (C) 2019 Tom Zanussi <zanussi@kernel.org>
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/trace_events.h>
     10
     11/*
     12 * This module is a simple test of basic functionality for in-kernel
     13 * synthetic event creation and generation, the first and second tests
     14 * using synth_event_gen_cmd_start() and synth_event_add_field(), the
     15 * third uses synth_event_create() to do it all at once with a static
     16 * field array.
     17 *
     18 * Following that are a few examples using the created events to test
     19 * various ways of tracing a synthetic event.
     20 *
     21 * To test, select CONFIG_SYNTH_EVENT_GEN_TEST and build the module.
     22 * Then:
     23 *
     24 * # insmod kernel/trace/synth_event_gen_test.ko
     25 * # cat /sys/kernel/debug/tracing/trace
     26 *
     27 * You should see several events in the trace buffer -
     28 * "create_synth_test", "empty_synth_test", and several instances of
     29 * "gen_synth_test".
     30 *
     31 * To remove the events, remove the module:
     32 *
     33 * # rmmod synth_event_gen_test
     34 *
     35 */
     36
     37static struct trace_event_file *create_synth_test;
     38static struct trace_event_file *empty_synth_test;
     39static struct trace_event_file *gen_synth_test;
     40
     41/*
     42 * Test to make sure we can create a synthetic event, then add more
     43 * fields.
     44 */
     45static int __init test_gen_synth_cmd(void)
     46{
     47	struct dynevent_cmd cmd;
     48	u64 vals[7];
     49	char *buf;
     50	int ret;
     51
     52	/* Create a buffer to hold the generated command */
     53	buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
     54	if (!buf)
     55		return -ENOMEM;
     56
     57	/* Before generating the command, initialize the cmd object */
     58	synth_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
     59
     60	/*
     61	 * Create the empty gen_synth_test synthetic event with the
     62	 * first 4 fields.
     63	 */
     64	ret = synth_event_gen_cmd_start(&cmd, "gen_synth_test", THIS_MODULE,
     65					"pid_t", "next_pid_field",
     66					"char[16]", "next_comm_field",
     67					"u64", "ts_ns",
     68					"u64", "ts_ms");
     69	if (ret)
     70		goto free;
     71
     72	/* Use synth_event_add_field to add the rest of the fields */
     73
     74	ret = synth_event_add_field(&cmd, "unsigned int", "cpu");
     75	if (ret)
     76		goto free;
     77
     78	ret = synth_event_add_field(&cmd, "char[64]", "my_string_field");
     79	if (ret)
     80		goto free;
     81
     82	ret = synth_event_add_field(&cmd, "int", "my_int_field");
     83	if (ret)
     84		goto free;
     85
     86	ret = synth_event_gen_cmd_end(&cmd);
     87	if (ret)
     88		goto free;
     89
     90	/*
     91	 * Now get the gen_synth_test event file.  We need to prevent
     92	 * the instance and event from disappearing from underneath
     93	 * us, which trace_get_event_file() does (though in this case
     94	 * we're using the top-level instance which never goes away).
     95	 */
     96	gen_synth_test = trace_get_event_file(NULL, "synthetic",
     97					      "gen_synth_test");
     98	if (IS_ERR(gen_synth_test)) {
     99		ret = PTR_ERR(gen_synth_test);
    100		goto delete;
    101	}
    102
    103	/* Enable the event or you won't see anything */
    104	ret = trace_array_set_clr_event(gen_synth_test->tr,
    105					"synthetic", "gen_synth_test", true);
    106	if (ret) {
    107		trace_put_event_file(gen_synth_test);
    108		goto delete;
    109	}
    110
    111	/* Create some bogus values just for testing */
    112
    113	vals[0] = 777;			/* next_pid_field */
    114	vals[1] = (u64)(long)"hula hoops";	/* next_comm_field */
    115	vals[2] = 1000000;		/* ts_ns */
    116	vals[3] = 1000;			/* ts_ms */
    117	vals[4] = raw_smp_processor_id(); /* cpu */
    118	vals[5] = (u64)(long)"thneed";	/* my_string_field */
    119	vals[6] = 598;			/* my_int_field */
    120
    121	/* Now generate a gen_synth_test event */
    122	ret = synth_event_trace_array(gen_synth_test, vals, ARRAY_SIZE(vals));
    123 out:
    124	return ret;
    125 delete:
    126	/* We got an error after creating the event, delete it */
    127	synth_event_delete("gen_synth_test");
    128 free:
    129	kfree(buf);
    130
    131	goto out;
    132}
    133
    134/*
    135 * Test to make sure we can create an initially empty synthetic event,
    136 * then add all the fields.
    137 */
    138static int __init test_empty_synth_event(void)
    139{
    140	struct dynevent_cmd cmd;
    141	u64 vals[7];
    142	char *buf;
    143	int ret;
    144
    145	/* Create a buffer to hold the generated command */
    146	buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
    147	if (!buf)
    148		return -ENOMEM;
    149
    150	/* Before generating the command, initialize the cmd object */
    151	synth_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
    152
    153	/*
    154	 * Create the empty_synth_test synthetic event with no fields.
    155	 */
    156	ret = synth_event_gen_cmd_start(&cmd, "empty_synth_test", THIS_MODULE);
    157	if (ret)
    158		goto free;
    159
    160	/* Use synth_event_add_field to add all of the fields */
    161
    162	ret = synth_event_add_field(&cmd, "pid_t", "next_pid_field");
    163	if (ret)
    164		goto free;
    165
    166	ret = synth_event_add_field(&cmd, "char[16]", "next_comm_field");
    167	if (ret)
    168		goto free;
    169
    170	ret = synth_event_add_field(&cmd, "u64", "ts_ns");
    171	if (ret)
    172		goto free;
    173
    174	ret = synth_event_add_field(&cmd, "u64", "ts_ms");
    175	if (ret)
    176		goto free;
    177
    178	ret = synth_event_add_field(&cmd, "unsigned int", "cpu");
    179	if (ret)
    180		goto free;
    181
    182	ret = synth_event_add_field(&cmd, "char[64]", "my_string_field");
    183	if (ret)
    184		goto free;
    185
    186	ret = synth_event_add_field(&cmd, "int", "my_int_field");
    187	if (ret)
    188		goto free;
    189
    190	/* All fields have been added, close and register the synth event */
    191
    192	ret = synth_event_gen_cmd_end(&cmd);
    193	if (ret)
    194		goto free;
    195
    196	/*
    197	 * Now get the empty_synth_test event file.  We need to
    198	 * prevent the instance and event from disappearing from
    199	 * underneath us, which trace_get_event_file() does (though in
    200	 * this case we're using the top-level instance which never
    201	 * goes away).
    202	 */
    203	empty_synth_test = trace_get_event_file(NULL, "synthetic",
    204						"empty_synth_test");
    205	if (IS_ERR(empty_synth_test)) {
    206		ret = PTR_ERR(empty_synth_test);
    207		goto delete;
    208	}
    209
    210	/* Enable the event or you won't see anything */
    211	ret = trace_array_set_clr_event(empty_synth_test->tr,
    212					"synthetic", "empty_synth_test", true);
    213	if (ret) {
    214		trace_put_event_file(empty_synth_test);
    215		goto delete;
    216	}
    217
    218	/* Create some bogus values just for testing */
    219
    220	vals[0] = 777;			/* next_pid_field */
    221	vals[1] = (u64)(long)"tiddlywinks";	/* next_comm_field */
    222	vals[2] = 1000000;		/* ts_ns */
    223	vals[3] = 1000;			/* ts_ms */
    224	vals[4] = raw_smp_processor_id(); /* cpu */
    225	vals[5] = (u64)(long)"thneed_2.0";	/* my_string_field */
    226	vals[6] = 399;			/* my_int_field */
    227
    228	/* Now trace an empty_synth_test event */
    229	ret = synth_event_trace_array(empty_synth_test, vals, ARRAY_SIZE(vals));
    230 out:
    231	return ret;
    232 delete:
    233	/* We got an error after creating the event, delete it */
    234	synth_event_delete("empty_synth_test");
    235 free:
    236	kfree(buf);
    237
    238	goto out;
    239}
    240
    241static struct synth_field_desc create_synth_test_fields[] = {
    242	{ .type = "pid_t",		.name = "next_pid_field" },
    243	{ .type = "char[16]",		.name = "next_comm_field" },
    244	{ .type = "u64",		.name = "ts_ns" },
    245	{ .type = "char[]",		.name = "dynstring_field_1" },
    246	{ .type = "u64",		.name = "ts_ms" },
    247	{ .type = "unsigned int",	.name = "cpu" },
    248	{ .type = "char[64]",		.name = "my_string_field" },
    249	{ .type = "char[]",		.name = "dynstring_field_2" },
    250	{ .type = "int",		.name = "my_int_field" },
    251};
    252
    253/*
    254 * Test synthetic event creation all at once from array of field
    255 * descriptors.
    256 */
    257static int __init test_create_synth_event(void)
    258{
    259	u64 vals[9];
    260	int ret;
    261
    262	/* Create the create_synth_test event with the fields above */
    263	ret = synth_event_create("create_synth_test",
    264				 create_synth_test_fields,
    265				 ARRAY_SIZE(create_synth_test_fields),
    266				 THIS_MODULE);
    267	if (ret)
    268		goto out;
    269
    270	/*
    271	 * Now get the create_synth_test event file.  We need to
    272	 * prevent the instance and event from disappearing from
    273	 * underneath us, which trace_get_event_file() does (though in
    274	 * this case we're using the top-level instance which never
    275	 * goes away).
    276	 */
    277	create_synth_test = trace_get_event_file(NULL, "synthetic",
    278						 "create_synth_test");
    279	if (IS_ERR(create_synth_test)) {
    280		ret = PTR_ERR(create_synth_test);
    281		goto delete;
    282	}
    283
    284	/* Enable the event or you won't see anything */
    285	ret = trace_array_set_clr_event(create_synth_test->tr,
    286					"synthetic", "create_synth_test", true);
    287	if (ret) {
    288		trace_put_event_file(create_synth_test);
    289		goto delete;
    290	}
    291
    292	/* Create some bogus values just for testing */
    293
    294	vals[0] = 777;			/* next_pid_field */
    295	vals[1] = (u64)(long)"tiddlywinks";	/* next_comm_field */
    296	vals[2] = 1000000;		/* ts_ns */
    297	vals[3] = (u64)(long)"xrayspecs";	/* dynstring_field_1 */
    298	vals[4] = 1000;			/* ts_ms */
    299	vals[5] = raw_smp_processor_id(); /* cpu */
    300	vals[6] = (u64)(long)"thneed";	/* my_string_field */
    301	vals[7] = (u64)(long)"kerplunk";	/* dynstring_field_2 */
    302	vals[8] = 398;			/* my_int_field */
    303
    304	/* Now generate a create_synth_test event */
    305	ret = synth_event_trace_array(create_synth_test, vals, ARRAY_SIZE(vals));
    306 out:
    307	return ret;
    308 delete:
    309	/* We got an error after creating the event, delete it */
    310	synth_event_delete("create_synth_test");
    311
    312	goto out;
    313}
    314
    315/*
    316 * Test tracing a synthetic event by reserving trace buffer space,
    317 * then filling in fields one after another.
    318 */
    319static int __init test_add_next_synth_val(void)
    320{
    321	struct synth_event_trace_state trace_state;
    322	int ret;
    323
    324	/* Start by reserving space in the trace buffer */
    325	ret = synth_event_trace_start(gen_synth_test, &trace_state);
    326	if (ret)
    327		return ret;
    328
    329	/* Write some bogus values into the trace buffer, one after another */
    330
    331	/* next_pid_field */
    332	ret = synth_event_add_next_val(777, &trace_state);
    333	if (ret)
    334		goto out;
    335
    336	/* next_comm_field */
    337	ret = synth_event_add_next_val((u64)(long)"slinky", &trace_state);
    338	if (ret)
    339		goto out;
    340
    341	/* ts_ns */
    342	ret = synth_event_add_next_val(1000000, &trace_state);
    343	if (ret)
    344		goto out;
    345
    346	/* ts_ms */
    347	ret = synth_event_add_next_val(1000, &trace_state);
    348	if (ret)
    349		goto out;
    350
    351	/* cpu */
    352	ret = synth_event_add_next_val(raw_smp_processor_id(), &trace_state);
    353	if (ret)
    354		goto out;
    355
    356	/* my_string_field */
    357	ret = synth_event_add_next_val((u64)(long)"thneed_2.01", &trace_state);
    358	if (ret)
    359		goto out;
    360
    361	/* my_int_field */
    362	ret = synth_event_add_next_val(395, &trace_state);
    363 out:
    364	/* Finally, commit the event */
    365	ret = synth_event_trace_end(&trace_state);
    366
    367	return ret;
    368}
    369
    370/*
    371 * Test tracing a synthetic event by reserving trace buffer space,
    372 * then filling in fields using field names, which can be done in any
    373 * order.
    374 */
    375static int __init test_add_synth_val(void)
    376{
    377	struct synth_event_trace_state trace_state;
    378	int ret;
    379
    380	/* Start by reserving space in the trace buffer */
    381	ret = synth_event_trace_start(gen_synth_test, &trace_state);
    382	if (ret)
    383		return ret;
    384
    385	/* Write some bogus values into the trace buffer, using field names */
    386
    387	ret = synth_event_add_val("ts_ns", 1000000, &trace_state);
    388	if (ret)
    389		goto out;
    390
    391	ret = synth_event_add_val("ts_ms", 1000, &trace_state);
    392	if (ret)
    393		goto out;
    394
    395	ret = synth_event_add_val("cpu", raw_smp_processor_id(), &trace_state);
    396	if (ret)
    397		goto out;
    398
    399	ret = synth_event_add_val("next_pid_field", 777, &trace_state);
    400	if (ret)
    401		goto out;
    402
    403	ret = synth_event_add_val("next_comm_field", (u64)(long)"silly putty",
    404				  &trace_state);
    405	if (ret)
    406		goto out;
    407
    408	ret = synth_event_add_val("my_string_field", (u64)(long)"thneed_9",
    409				  &trace_state);
    410	if (ret)
    411		goto out;
    412
    413	ret = synth_event_add_val("my_int_field", 3999, &trace_state);
    414 out:
    415	/* Finally, commit the event */
    416	ret = synth_event_trace_end(&trace_state);
    417
    418	return ret;
    419}
    420
    421/*
    422 * Test tracing a synthetic event all at once from array of values.
    423 */
    424static int __init test_trace_synth_event(void)
    425{
    426	int ret;
    427
    428	/* Trace some bogus values just for testing */
    429	ret = synth_event_trace(create_synth_test, 9,	/* number of values */
    430				(u64)444,		/* next_pid_field */
    431				(u64)(long)"clackers",	/* next_comm_field */
    432				(u64)1000000,		/* ts_ns */
    433				(u64)(long)"viewmaster",/* dynstring_field_1 */
    434				(u64)1000,		/* ts_ms */
    435				(u64)raw_smp_processor_id(), /* cpu */
    436				(u64)(long)"Thneed",	/* my_string_field */
    437				(u64)(long)"yoyos",	/* dynstring_field_2 */
    438				(u64)999);		/* my_int_field */
    439	return ret;
    440}
    441
    442static int __init synth_event_gen_test_init(void)
    443{
    444	int ret;
    445
    446	ret = test_gen_synth_cmd();
    447	if (ret)
    448		return ret;
    449
    450	ret = test_empty_synth_event();
    451	if (ret) {
    452		WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
    453						  "synthetic",
    454						  "gen_synth_test", false));
    455		trace_put_event_file(gen_synth_test);
    456		WARN_ON(synth_event_delete("gen_synth_test"));
    457		goto out;
    458	}
    459
    460	ret = test_create_synth_event();
    461	if (ret) {
    462		WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
    463						  "synthetic",
    464						  "gen_synth_test", false));
    465		trace_put_event_file(gen_synth_test);
    466		WARN_ON(synth_event_delete("gen_synth_test"));
    467
    468		WARN_ON(trace_array_set_clr_event(empty_synth_test->tr,
    469						  "synthetic",
    470						  "empty_synth_test", false));
    471		trace_put_event_file(empty_synth_test);
    472		WARN_ON(synth_event_delete("empty_synth_test"));
    473		goto out;
    474	}
    475
    476	ret = test_add_next_synth_val();
    477	WARN_ON(ret);
    478
    479	ret = test_add_synth_val();
    480	WARN_ON(ret);
    481
    482	ret = test_trace_synth_event();
    483	WARN_ON(ret);
    484 out:
    485	return ret;
    486}
    487
    488static void __exit synth_event_gen_test_exit(void)
    489{
    490	/* Disable the event or you can't remove it */
    491	WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
    492					  "synthetic",
    493					  "gen_synth_test", false));
    494
    495	/* Now give the file and instance back */
    496	trace_put_event_file(gen_synth_test);
    497
    498	/* Now unregister and free the synthetic event */
    499	WARN_ON(synth_event_delete("gen_synth_test"));
    500
    501	/* Disable the event or you can't remove it */
    502	WARN_ON(trace_array_set_clr_event(empty_synth_test->tr,
    503					  "synthetic",
    504					  "empty_synth_test", false));
    505
    506	/* Now give the file and instance back */
    507	trace_put_event_file(empty_synth_test);
    508
    509	/* Now unregister and free the synthetic event */
    510	WARN_ON(synth_event_delete("empty_synth_test"));
    511
    512	/* Disable the event or you can't remove it */
    513	WARN_ON(trace_array_set_clr_event(create_synth_test->tr,
    514					  "synthetic",
    515					  "create_synth_test", false));
    516
    517	/* Now give the file and instance back */
    518	trace_put_event_file(create_synth_test);
    519
    520	/* Now unregister and free the synthetic event */
    521	WARN_ON(synth_event_delete("create_synth_test"));
    522}
    523
    524module_init(synth_event_gen_test_init)
    525module_exit(synth_event_gen_test_exit)
    526
    527MODULE_AUTHOR("Tom Zanussi");
    528MODULE_DESCRIPTION("synthetic event generation test");
    529MODULE_LICENSE("GPL v2");