162306a36Sopenharmony_ci#!/usr/bin/env python3 262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-only 362306a36Sopenharmony_ci# 462306a36Sopenharmony_ci# Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org> 562306a36Sopenharmony_ci# 662306a36Sopenharmony_ci# dot2k: transform dot files into a monitor for the Linux kernel. 762306a36Sopenharmony_ci# 862306a36Sopenharmony_ci# For further information, see: 962306a36Sopenharmony_ci# Documentation/trace/rv/da_monitor_synthesis.rst 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cifrom dot2.dot2c import Dot2c 1262306a36Sopenharmony_ciimport platform 1362306a36Sopenharmony_ciimport os 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciclass dot2k(Dot2c): 1662306a36Sopenharmony_ci monitor_types = { "global" : 1, "per_cpu" : 2, "per_task" : 3 } 1762306a36Sopenharmony_ci monitor_templates_dir = "dot2k/rv_templates/" 1862306a36Sopenharmony_ci monitor_type = "per_cpu" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci def __init__(self, file_path, MonitorType): 2162306a36Sopenharmony_ci super().__init__(file_path) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci self.monitor_type = self.monitor_types.get(MonitorType) 2462306a36Sopenharmony_ci if self.monitor_type == None: 2562306a36Sopenharmony_ci raise Exception("Unknown monitor type: %s" % MonitorType) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci self.monitor_type = MonitorType 2862306a36Sopenharmony_ci self.__fill_rv_templates_dir() 2962306a36Sopenharmony_ci self.main_c = self.__open_file(self.monitor_templates_dir + "main_" + MonitorType + ".c") 3062306a36Sopenharmony_ci self.enum_suffix = "_%s" % self.name 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci def __fill_rv_templates_dir(self): 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if os.path.exists(self.monitor_templates_dir) == True: 3562306a36Sopenharmony_ci return 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if platform.system() != "Linux": 3862306a36Sopenharmony_ci raise Exception("I can only run on Linux.") 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci kernel_path = "/lib/modules/%s/build/tools/verification/dot2/dot2k_templates/" % (platform.release()) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if os.path.exists(kernel_path) == True: 4362306a36Sopenharmony_ci self.monitor_templates_dir = kernel_path 4462306a36Sopenharmony_ci return 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if os.path.exists("/usr/share/dot2/dot2k_templates/") == True: 4762306a36Sopenharmony_ci self.monitor_templates_dir = "/usr/share/dot2/dot2k_templates/" 4862306a36Sopenharmony_ci return 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci raise Exception("Could not find the template directory, do you have the kernel source installed?") 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci def __open_file(self, path): 5462306a36Sopenharmony_ci try: 5562306a36Sopenharmony_ci fd = open(path) 5662306a36Sopenharmony_ci except OSError: 5762306a36Sopenharmony_ci raise Exception("Cannot open the file: %s" % path) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci content = fd.read() 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return content 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci def __buff_to_string(self, buff): 6462306a36Sopenharmony_ci string = "" 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci for line in buff: 6762306a36Sopenharmony_ci string = string + line + "\n" 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci # cut off the last \n 7062306a36Sopenharmony_ci return string[:-1] 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci def fill_tracepoint_handlers_skel(self): 7362306a36Sopenharmony_ci buff = [] 7462306a36Sopenharmony_ci for event in self.events: 7562306a36Sopenharmony_ci buff.append("static void handle_%s(void *data, /* XXX: fill header */)" % event) 7662306a36Sopenharmony_ci buff.append("{") 7762306a36Sopenharmony_ci if self.monitor_type == "per_task": 7862306a36Sopenharmony_ci buff.append("\tstruct task_struct *p = /* XXX: how do I get p? */;"); 7962306a36Sopenharmony_ci buff.append("\tda_handle_event_%s(p, %s%s);" % (self.name, event, self.enum_suffix)); 8062306a36Sopenharmony_ci else: 8162306a36Sopenharmony_ci buff.append("\tda_handle_event_%s(%s%s);" % (self.name, event, self.enum_suffix)); 8262306a36Sopenharmony_ci buff.append("}") 8362306a36Sopenharmony_ci buff.append("") 8462306a36Sopenharmony_ci return self.__buff_to_string(buff) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci def fill_tracepoint_attach_probe(self): 8762306a36Sopenharmony_ci buff = [] 8862306a36Sopenharmony_ci for event in self.events: 8962306a36Sopenharmony_ci buff.append("\trv_attach_trace_probe(\"%s\", /* XXX: tracepoint */, handle_%s);" % (self.name, event)) 9062306a36Sopenharmony_ci return self.__buff_to_string(buff) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci def fill_tracepoint_detach_helper(self): 9362306a36Sopenharmony_ci buff = [] 9462306a36Sopenharmony_ci for event in self.events: 9562306a36Sopenharmony_ci buff.append("\trv_detach_trace_probe(\"%s\", /* XXX: tracepoint */, handle_%s);" % (self.name, event)) 9662306a36Sopenharmony_ci return self.__buff_to_string(buff) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci def fill_main_c(self): 9962306a36Sopenharmony_ci main_c = self.main_c 10062306a36Sopenharmony_ci min_type = self.get_minimun_type() 10162306a36Sopenharmony_ci nr_events = self.events.__len__() 10262306a36Sopenharmony_ci tracepoint_handlers = self.fill_tracepoint_handlers_skel() 10362306a36Sopenharmony_ci tracepoint_attach = self.fill_tracepoint_attach_probe() 10462306a36Sopenharmony_ci tracepoint_detach = self.fill_tracepoint_detach_helper() 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci main_c = main_c.replace("MIN_TYPE", min_type) 10762306a36Sopenharmony_ci main_c = main_c.replace("MODEL_NAME", self.name) 10862306a36Sopenharmony_ci main_c = main_c.replace("NR_EVENTS", str(nr_events)) 10962306a36Sopenharmony_ci main_c = main_c.replace("TRACEPOINT_HANDLERS_SKEL", tracepoint_handlers) 11062306a36Sopenharmony_ci main_c = main_c.replace("TRACEPOINT_ATTACH", tracepoint_attach) 11162306a36Sopenharmony_ci main_c = main_c.replace("TRACEPOINT_DETACH", tracepoint_detach) 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return main_c 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci def fill_model_h_header(self): 11662306a36Sopenharmony_ci buff = [] 11762306a36Sopenharmony_ci buff.append("/*") 11862306a36Sopenharmony_ci buff.append(" * Automatically generated C representation of %s automaton" % (self.name)) 11962306a36Sopenharmony_ci buff.append(" * For further information about this format, see kernel documentation:") 12062306a36Sopenharmony_ci buff.append(" * Documentation/trace/rv/deterministic_automata.rst") 12162306a36Sopenharmony_ci buff.append(" */") 12262306a36Sopenharmony_ci buff.append("") 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return buff 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci def fill_model_h(self): 12762306a36Sopenharmony_ci # 12862306a36Sopenharmony_ci # Adjust the definition names 12962306a36Sopenharmony_ci # 13062306a36Sopenharmony_ci self.enum_states_def = "states_%s" % self.name 13162306a36Sopenharmony_ci self.enum_events_def = "events_%s" % self.name 13262306a36Sopenharmony_ci self.struct_automaton_def = "automaton_%s" % self.name 13362306a36Sopenharmony_ci self.var_automaton_def = "automaton_%s" % self.name 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci buff = self.fill_model_h_header() 13662306a36Sopenharmony_ci buff += self.format_model() 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return self.__buff_to_string(buff) 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci def __create_directory(self): 14162306a36Sopenharmony_ci try: 14262306a36Sopenharmony_ci os.mkdir(self.name) 14362306a36Sopenharmony_ci except FileExistsError: 14462306a36Sopenharmony_ci return 14562306a36Sopenharmony_ci except: 14662306a36Sopenharmony_ci print("Fail creating the output dir: %s" % self.name) 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci def __create_file(self, file_name, content): 14962306a36Sopenharmony_ci path = "%s/%s" % (self.name, file_name) 15062306a36Sopenharmony_ci try: 15162306a36Sopenharmony_ci file = open(path, 'w') 15262306a36Sopenharmony_ci except FileExistsError: 15362306a36Sopenharmony_ci return 15462306a36Sopenharmony_ci except: 15562306a36Sopenharmony_ci print("Fail creating file: %s" % path) 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci file.write(content) 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci file.close() 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci def __get_main_name(self): 16262306a36Sopenharmony_ci path = "%s/%s" % (self.name, "main.c") 16362306a36Sopenharmony_ci if os.path.exists(path) == False: 16462306a36Sopenharmony_ci return "main.c" 16562306a36Sopenharmony_ci return "__main.c" 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci def print_files(self): 16862306a36Sopenharmony_ci main_c = self.fill_main_c() 16962306a36Sopenharmony_ci model_h = self.fill_model_h() 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci self.__create_directory() 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci path = "%s.c" % self.name 17462306a36Sopenharmony_ci self.__create_file(path, main_c) 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci path = "%s.h" % self.name 17762306a36Sopenharmony_ci self.__create_file(path, model_h) 178