xref: /aosp_15_r20/external/trace-cmd/lib/trace-cmd/trace-blk-hack.c (revision 58e6ee5f017f6a8912852c892d18457e4bafb554)
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <[email protected]>
4  *
5  */
6 #include <stdio.h>
7 #include "trace-cmd.h"
8 #include "trace-local.h"
9 
10 static const char blk_event_start[] =
11 	"name: blktrace\n"
12 	"ID: %d\n"
13 	"format:\n"
14 	"\tfield:unsigned short common_type;\toffset:0;\tsize:2;\n"
15 	"\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\n"
16 	"\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\n"
17 	"\tfield:int common_pid;\toffset:4;\tsize:4;\n";
18 
19 static const char blk_body[] = "\n"
20 	"\tfield:u64 sector;\toffset:16;\tsize:8;\n"
21 	"\tfield:int bytes;\toffset:24;\tsize:4;\n"
22 	"\tfield:int action;\toffset:28;\tsize:4;\n"
23 	"\tfield:int pid;\toffset:32;\tsize:4;\n"
24 	"\tfield:int device;\toffset:36;\tsize:4;\n"
25 	"\tfield:int cpu;\toffset:40;\tsize:4;\n"
26 	"\tfield:short error;\toffset:44;\tsize:2;\n"
27 	"\tfield:short pdu_len;\toffset:46;\tsize:2;\n"
28 	"\tfield:void data;\toffset:48;\tsize:0;\n"
29 	"\n"
30 	"print fmt: \"%%d\", REC->pid\n";
31 
tracecmd_blk_hack(struct tracecmd_input * handle)32 int tracecmd_blk_hack(struct tracecmd_input *handle)
33 {
34 	struct tep_handle *pevent;
35 	struct tep_event *event;
36 	struct tep_format_field *field;
37 	char buf[4096]; /* way more than enough! */
38 	int id;
39 	int l;
40 	int r;
41 
42 	pevent = tracecmd_get_tep(handle);
43 
44 	/*
45 	 * Unfortunately, the TRACE_BLK has changed a bit.
46 	 * We need to test if various events exist to try
47 	 * to guess what event id TRACE_BLK would be.
48 	 */
49 
50 	/* It was originally behind the "power" event */
51 	event = tep_find_event_by_name(pevent, "ftrace", "power");
52 	if (event) {
53 		id = event->id + 1;
54 		goto found;
55 	}
56 
57 	/*
58 	 * But the power tracer is now in perf.
59 	 * Then it was after kmem_free
60 	 */
61 	event = tep_find_event_by_name(pevent, "ftrace", "kmem_free");
62 	if (event) {
63 		id = event->id + 1;
64 		goto found;
65 	}
66 
67 	/*
68 	 * But that then went away.
69 	 * Currently it should be behind the user stack.
70 	 */
71 	event = tep_find_event_by_name(pevent, "ftrace", "user_stack");
72 	if (event) {
73 		id = event->id + 1;
74 		goto found;
75 	}
76 	/* Give up :( */
77 	return -1;
78 
79  found:
80 	/*
81 	 * Blk events are not exported in the events directory.
82 	 * This is a hack to attempt to create a block event
83 	 * that we can read.
84 	 *
85 	 * We'll make a format file to look like this:
86 	 *
87 	 * name: blktrace
88 	 * ID: 13
89 	 * format:
90 	 *	field:unsigned short common_type;	offset:0;	size:2;
91 	 *	field:unsigned char common_flags;	offset:2;	size:1;
92 	 *	field:unsigned char common_preempt_count;	offset:3;	size:1;
93 	 *	field:int common_pid;	offset:4;	size:4;
94 	 *	field:int common_lock_depth;	offset:8;	size:4;
95 	 *
96 	 *	field:u64 sector;	offset:16;	size:8;
97 	 *	field:int bytes;	offset:32;	size:4;
98 	 *	field:int action;	offset:36;	size:4;
99 	 *	field:int pid;	offset:40;	size:4;
100 	 *	field:int device;	offset:44;	size:4;
101 	 *	field:int cpu;	offset:48;	size:4;
102 	 *	field:short error;	offset:52;	size:2;
103 	 *	field:short pdu_len;	offset:54;	size:2;
104 	 *	field:void data;	offset:60;	size:0;
105 	 *
106 	 * print fmt: "%d", REC->pid
107 	 *
108 	 * Note: the struct blk_io_trace is used directly and
109 	 * just the first parts of the struct are not used in order
110 	 * to not write over the ftrace data.
111 	 */
112 
113 	/* Make sure the common fields exist */
114 	field = tep_find_common_field(event, "common_type");
115 	if (!field || field->offset != 0 || field->size != 2)
116 		goto fail;
117 	field = tep_find_common_field(event, "common_flags");
118 	if (!field || field->offset != 2 || field->size != 1)
119 		goto fail;
120 	field = tep_find_common_field(event, "common_preempt_count");
121 	if (!field || field->offset != 3 || field->size != 1)
122 		goto fail;
123 	field = tep_find_common_field(event, "common_pid");
124 	if (!field || field->offset != 4 || field->size != 4)
125 		goto fail;
126 	r = sprintf(buf, blk_event_start, id);
127 	l = r;
128 
129 	/* lock depth is optional */
130 	field = tep_find_common_field(event, "common_lock_depth");
131 	if (field) {
132 		if (field->offset != 8 || field->size != 4)
133 			return -1;
134 		r = sprintf(buf+l, "\tfield:int common_lock_depth;\toffset:8;\tsize:4;\n");
135 		l += r;
136 	}
137 
138 	r = sprintf(buf+l, blk_body);
139 
140 	/* Parse this event */
141 	l += r;
142 	tep_parse_event(pevent, buf, l, "ftrace");
143 
144 	return 0;
145 
146  fail:
147 	return -1;
148 }
149