Commit | Line | Data |
---|---|---|
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 | ||
8 | from dot2.dot2c import Dot2c | |
9 | import platform | |
10 | import os | |
11 | ||
12 | class 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) |