Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

verification/dot2k: Auto patch current kernel source

dot2k suggests a list of changes to the kernel tree while adding a
monitor: edit tracepoints header, Makefile, Kconfig and moving the
monitor folder. Those changes can be easily run automatically.

Add a flag to dot2k to alter the kernel source.

The kernel source directory can be either assumed from the PWD, or from
the running kernel, if installed.
This feature works best if the kernel tree is a git repository, so that
its easier to make sure there are no unintended changes.

The main RV files (e.g. Makefile) have now a comment placeholder that
can be useful for manual editing (e.g. to know where to add new
monitors) and it is used by the script to append the required lines.

We also slightly adapt the file handling functions in dot2k: __open_file
is now called __read_file and also closes the file before returning the
content; __create_file is now a more general __write_file, we no longer
return on FileExistsError (not thrown while opening), a new
__create_file simply calls __write_file specifying the monitor folder in
the path.

Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Kacur <jkacur@redhat.com>
Link: https://lore.kernel.org/20241227144752.362911-8-gmonaco@redhat.com
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Gabriele Monaco and committed by
Steven Rostedt (Google)
de6f45c2 9c6cfe80

+86 -16
+1 -1
kernel/trace/rv/Kconfig
··· 26 26 Documentation/trace/rv/runtime-verification.rst 27 27 28 28 source "kernel/trace/rv/monitors/wip/Kconfig" 29 - 30 29 source "kernel/trace/rv/monitors/wwnr/Kconfig" 30 + # Add new monitors here 31 31 32 32 config RV_REACTORS 33 33 bool "Runtime verification reactors"
+1
kernel/trace/rv/Makefile
··· 5 5 obj-$(CONFIG_RV) += rv.o 6 6 obj-$(CONFIG_RV_MON_WIP) += monitors/wip/wip.o 7 7 obj-$(CONFIG_RV_MON_WWNR) += monitors/wwnr/wwnr.o 8 + # Add new monitors here 8 9 obj-$(CONFIG_RV_REACTORS) += rv_reactors.o 9 10 obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o 10 11 obj-$(CONFIG_RV_REACT_PANIC) += reactor_panic.o
+2
kernel/trace/rv/rv_trace.h
··· 58 58 ); 59 59 60 60 #include <monitors/wip/wip_trace.h> 61 + // Add new monitors based on CONFIG_DA_MON_EVENTS_IMPLICIT here 61 62 62 63 #endif /* CONFIG_DA_MON_EVENTS_IMPLICIT */ 63 64 ··· 118 117 ); 119 118 120 119 #include <monitors/wwnr/wwnr_trace.h> 120 + // Add new monitors based on CONFIG_DA_MON_EVENTS_ID here 121 121 122 122 #endif /* CONFIG_DA_MON_EVENTS_ID */ 123 123 #endif /* _TRACE_RV_H */
+4 -1
tools/verification/dot2/dot2k
··· 21 21 parser.add_argument('-t', "--monitor_type", dest="monitor_type", required=True) 22 22 parser.add_argument('-n', "--model_name", dest="model_name", required=False) 23 23 parser.add_argument("-D", "--description", dest="description", required=False) 24 + parser.add_argument("-a", "--auto_patch", dest="auto_patch", 25 + action="store_true", required=False, 26 + help="Patch the kernel in place") 24 27 params = parser.parse_args() 25 28 26 29 print("Opening and parsing the dot file %s" % params.dot_file) ··· 41 38 print(monitor.fill_tracepoint_tooltip()) 42 39 print(monitor.fill_makefile_tooltip()) 43 40 print(monitor.fill_kconfig_tooltip()) 44 - print(" - Move %s/ to the kernel's monitor directory (%s/monitors)" % (monitor.name, monitor.rv_dir)) 41 + print(monitor.fill_monitor_tooltip())
+78 -14
tools/verification/dot2/dot2k.py
··· 27 27 28 28 self.monitor_type = MonitorType 29 29 self.__fill_rv_templates_dir() 30 - self.main_c = self.__open_file(self.monitor_templates_dir + "main.c") 31 - self.trace_h = self.__open_file(self.monitor_templates_dir + "trace.h") 32 - self.kconfig = self.__open_file(self.monitor_templates_dir + "Kconfig") 30 + self.main_c = self.__read_file(self.monitor_templates_dir + "main.c") 31 + self.trace_h = self.__read_file(self.monitor_templates_dir + "trace.h") 32 + self.kconfig = self.__read_file(self.monitor_templates_dir + "Kconfig") 33 33 self.enum_suffix = "_%s" % self.name 34 34 self.description = extra_params.get("description", self.name) or "auto-generated" 35 + self.auto_patch = extra_params.get("auto_patch") 36 + if self.auto_patch: 37 + self.__fill_rv_kernel_dir() 35 38 36 39 def __fill_rv_templates_dir(self): 37 40 ··· 42 39 return 43 40 44 41 if platform.system() != "Linux": 45 - raise Exception("I can only run on Linux.") 42 + raise OSError("I can only run on Linux.") 46 43 47 44 kernel_path = "/lib/modules/%s/build/tools/verification/dot2/dot2k_templates/" % (platform.release()) 48 45 ··· 54 51 self.monitor_templates_dir = "/usr/share/dot2/dot2k_templates/" 55 52 return 56 53 57 - raise Exception("Could not find the template directory, do you have the kernel source installed?") 54 + raise FileNotFoundError("Could not find the template directory, do you have the kernel source installed?") 58 55 56 + def __fill_rv_kernel_dir(self): 59 57 60 - def __open_file(self, path): 58 + # first try if we are running in the kernel tree root 59 + if os.path.exists(self.rv_dir): 60 + return 61 + 62 + # offset if we are running inside the kernel tree from verification/dot2 63 + kernel_path = os.path.join("../..", self.rv_dir) 64 + 65 + if os.path.exists(kernel_path): 66 + self.rv_dir = kernel_path 67 + return 68 + 69 + if platform.system() != "Linux": 70 + raise OSError("I can only run on Linux.") 71 + 72 + kernel_path = os.path.join("/lib/modules/%s/build" % platform.release(), self.rv_dir) 73 + 74 + # if the current kernel is from a distro this may not be a full kernel tree 75 + # verify that one of the files we are going to modify is available 76 + if os.path.exists(os.path.join(kernel_path, "rv_trace.h")): 77 + self.rv_dir = kernel_path 78 + return 79 + 80 + raise FileNotFoundError("Could not find the rv directory, do you have the kernel source installed?") 81 + 82 + def __read_file(self, path): 61 83 try: 62 - fd = open(path) 84 + fd = open(path, 'r') 63 85 except OSError: 64 86 raise Exception("Cannot open the file: %s" % path) 65 87 66 88 content = fd.read() 67 89 90 + fd.close() 68 91 return content 69 92 70 93 def __buff_to_string(self, buff): ··· 231 202 kconfig = kconfig.replace("%%DESCRIPTION%%", self.description) 232 203 return kconfig 233 204 205 + def __patch_file(self, file, marker, line): 206 + file_to_patch = os.path.join(self.rv_dir, file) 207 + content = self.__read_file(file_to_patch) 208 + content = content.replace(marker, line + "\n" + marker) 209 + self.__write_file(file_to_patch, content) 210 + 234 211 def fill_tracepoint_tooltip(self): 235 212 monitor_class_type = self.fill_monitor_class_type() 213 + if self.auto_patch: 214 + self.__patch_file("rv_trace.h", 215 + "// Add new monitors based on CONFIG_%s here" % monitor_class_type, 216 + "#include <monitors/%s/%s_trace.h>" % (self.name, self.name)) 217 + return " - Patching %s/rv_trace.h, double check the result" % self.rv_dir 218 + 236 219 return """ - Edit %s/rv_trace.h: 237 220 Add this line where other tracepoints are included and %s is defined: 238 221 #include <monitors/%s/%s_trace.h> 239 222 """ % (self.rv_dir, monitor_class_type, self.name, self.name) 240 223 241 224 def fill_kconfig_tooltip(self): 225 + if self.auto_patch: 226 + self.__patch_file("Kconfig", 227 + "# Add new monitors here", 228 + "source \"kernel/trace/rv/monitors/%s/Kconfig\"" % (self.name)) 229 + return " - Patching %s/Kconfig, double check the result" % self.rv_dir 230 + 242 231 return """ - Edit %s/Kconfig: 243 232 Add this line where other monitors are included: 244 233 source \"kernel/trace/rv/monitors/%s/Kconfig\" ··· 265 218 def fill_makefile_tooltip(self): 266 219 name = self.name 267 220 name_up = name.upper() 221 + if self.auto_patch: 222 + self.__patch_file("Makefile", 223 + "# Add new monitors here", 224 + "obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o" % (name_up, name, name)) 225 + return " - Patching %s/Makefile, double check the result" % self.rv_dir 226 + 268 227 return """ - Edit %s/Makefile: 269 228 Add this line where other monitors are included: 270 229 obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o 271 230 """ % (self.rv_dir, name_up, name, name) 272 231 232 + def fill_monitor_tooltip(self): 233 + if self.auto_patch: 234 + return " - Monitor created in %s/monitors/%s" % (self.rv_dir, self. name) 235 + return " - Move %s/ to the kernel's monitor directory (%s/monitors)" % (self.name, self.rv_dir) 236 + 273 237 def __create_directory(self): 238 + path = self.name 239 + if self.auto_patch: 240 + path = os.path.join(self.rv_dir, "monitors", path) 274 241 try: 275 - os.mkdir(self.name) 242 + os.mkdir(path) 276 243 except FileExistsError: 277 244 return 278 245 except: 279 246 print("Fail creating the output dir: %s" % self.name) 280 247 281 - def __create_file(self, file_name, content): 282 - path = "%s/%s" % (self.name, file_name) 248 + def __write_file(self, file_name, content): 283 249 try: 284 - file = open(path, 'w') 285 - except FileExistsError: 286 - return 250 + file = open(file_name, 'w') 287 251 except: 288 - print("Fail creating file: %s" % path) 252 + print("Fail writing to file: %s" % file_name) 289 253 290 254 file.write(content) 291 255 292 256 file.close() 257 + 258 + def __create_file(self, file_name, content): 259 + path = "%s/%s" % (self.name, file_name) 260 + if self.auto_patch: 261 + path = os.path.join(self.rv_dir, "monitors", path) 262 + self.__write_file(path, content) 293 263 294 264 def __get_main_name(self): 295 265 path = "%s/%s" % (self.name, "main.c")