tools/rv: Add dot2k
[linux-block.git] / tools / verification / dot2 / dot2k.py
CommitLineData
24bce201
DBO
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0-only
3#
4# Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org>
5#
6# dot2k: transform dot files into a monitor for the Linux kernel.
7
8from dot2.dot2c import Dot2c
9import platform
10import os
11
12class dot2k(Dot2c):
13 monitor_types = { "global" : 1, "per_cpu" : 2, "per_task" : 3 }
14 monitor_templates_dir = "dot2k/rv_templates/"
15 monitor_type = "per_cpu"
16
17 def __init__(self, file_path, MonitorType):
18 super().__init__(file_path)
19
20 self.monitor_type = self.monitor_types.get(MonitorType)
21 if self.monitor_type == None:
22 raise Exception("Unknown monitor type: %s" % MonitorType)
23
24 self.monitor_type = MonitorType
25 self.__fill_rv_templates_dir()
26 self.main_c = self.__open_file(self.monitor_templates_dir + "main_" + MonitorType + ".c")
27 self.enum_suffix = "_%s" % self.name
28
29 def __fill_rv_templates_dir(self):
30
31 if os.path.exists(self.monitor_templates_dir) == True:
32 return
33
34 if platform.system() != "Linux":
35 raise Exception("I can only run on Linux.")
36
37 kernel_path = "/lib/modules/%s/build/tools/verification/dot2/dot2k_templates/" % (platform.release())
38
39 if os.path.exists(kernel_path) == True:
40 self.monitor_templates_dir = kernel_path
41 return
42
43 if os.path.exists("/usr/share/dot2/dot2k_templates/") == True:
44 self.monitor_templates_dir = "/usr/share/dot2/dot2k_templates/"
45 return
46
47 raise Exception("Could not find the template directory, do you have the kernel source installed?")
48
49
50 def __open_file(self, path):
51 try:
52 fd = open(path)
53 except OSError:
54 raise Exception("Cannot open the file: %s" % path)
55
56 content = fd.read()
57
58 return content
59
60 def __buff_to_string(self, buff):
61 string = ""
62
63 for line in buff:
64 string = string + line + "\n"
65
66 # cut off the last \n
67 return string[:-1]
68
69 def fill_tracepoint_handlers_skel(self):
70 buff = []
71 for event in self.events:
72 buff.append("static void handle_%s(void *data, /* XXX: fill header */)" % event)
73 buff.append("{")
74 if self.monitor_type == "per_task":
75 buff.append("\tstruct task_struct *p = /* XXX: how do I get p? */;");
76 buff.append("\tda_handle_event_%s(p, %s%s);" % (self.name, event, self.enum_suffix));
77 else:
78 buff.append("\tda_handle_event_%s(%s%s);" % (self.name, event, self.enum_suffix));
79 buff.append("}")
80 buff.append("")
81 return self.__buff_to_string(buff)
82
83 def fill_tracepoint_attach_probe(self):
84 buff = []
85 for event in self.events:
86 buff.append("\trv_attach_trace_probe(\"%s\", /* XXX: tracepoint */, handle_%s);" % (self.name, event))
87 return self.__buff_to_string(buff)
88
89 def fill_tracepoint_detach_helper(self):
90 buff = []
91 for event in self.events:
92 buff.append("\trv_detach_trace_probe(\"%s\", /* XXX: tracepoint */, handle_%s);" % (self.name, event))
93 return self.__buff_to_string(buff)
94
95 def fill_main_c(self):
96 main_c = self.main_c
97 min_type = self.get_minimun_type()
98 nr_events = self.events.__len__()
99 tracepoint_handlers = self.fill_tracepoint_handlers_skel()
100 tracepoint_attach = self.fill_tracepoint_attach_probe()
101 tracepoint_detach = self.fill_tracepoint_detach_helper()
102
103 main_c = main_c.replace("MIN_TYPE", min_type)
104 main_c = main_c.replace("MODEL_NAME", self.name)
105 main_c = main_c.replace("NR_EVENTS", str(nr_events))
106 main_c = main_c.replace("TRACEPOINT_HANDLERS_SKEL", tracepoint_handlers)
107 main_c = main_c.replace("TRACEPOINT_ATTACH", tracepoint_attach)
108 main_c = main_c.replace("TRACEPOINT_DETACH", tracepoint_detach)
109
110 return main_c
111
112 def fill_model_h_header(self):
113 buff = []
114 buff.append("/*")
115 buff.append(" * Automatically generated C representation of %s automaton" % (self.name))
116 buff.append(" * For further information about this format, see kernel documentation:")
117 buff.append(" * Documentation/trace/rv/deterministic_automata.rst")
118 buff.append(" */")
119 buff.append("")
120
121 return buff
122
123 def fill_model_h(self):
124 #
125 # Adjust the definition names
126 #
127 self.enum_states_def = "states_%s" % self.name
128 self.enum_events_def = "events_%s" % self.name
129 self.struct_automaton_def = "automaton_%s" % self.name
130 self.var_automaton_def = "automaton_%s" % self.name
131
132 buff = self.fill_model_h_header()
133 buff += self.format_model()
134
135 return self.__buff_to_string(buff)
136
137 def __create_directory(self):
138 try:
139 os.mkdir(self.name)
140 except FileExistsError:
141 return
142 except:
143 print("Fail creating the output dir: %s" % self.name)
144
145 def __create_file(self, file_name, content):
146 path = "%s/%s" % (self.name, file_name)
147 try:
148 file = open(path, 'w')
149 except FileExistsError:
150 return
151 except:
152 print("Fail creating file: %s" % path)
153
154 file.write(content)
155
156 file.close()
157
158 def __get_main_name(self):
159 path = "%s/%s" % (self.name, "main.c")
160 if os.path.exists(path) == False:
161 return "main.c"
162 return "__main.c"
163
164 def print_files(self):
165 main_c = self.fill_main_c()
166 model_h = self.fill_model_h()
167
168 self.__create_directory()
169
170 path = "%s.c" % self.name
171 self.__create_file(path, main_c)
172
173 path = "%s.h" % self.name
174 self.__create_file(path, model_h)