&compileCommands);
21 | std::string getSourceCode(const std::string &sourceFile);
22 |
23 | std::string getClangBuiltInIncludePath(const std::string &fullCallPath);
24 | }
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/clang-proc/vmlinux-additional_defs.json:
--------------------------------------------------------------------------------
1 | ["__replacement______UNIQUE_ID__(prefix)=__unique##prefix"]
2 |
--------------------------------------------------------------------------------
/clang-proc/vmlinux-macro_replacement.json:
--------------------------------------------------------------------------------
1 | {
2 | "__get_user(x, ptr)" : "__replacement____get_user__(x,ptr)",
3 | "__put_user(x, ptr)" : "__replacement____put_user__(x,ptr)",
4 | "__UNIQUE_ID(prefix)": "__replacement______UNIQUE_ID__(prefix)",
5 | "BUG_ON(condition)": "__replacement____BUG_ON__(condition)",
6 | "wait_event_interruptible(wq_head, condition)": "__replacement__wait_event_interruptible__(wq_head,condition)",
7 | "wait_event_interruptible_timeout(wq_head, condition, timeout)": "__replacement__wait_event_interruptible_timeout__(wq_head,condition,timeout)",
8 | "WARN_ON(condition)": "__replacement__WARN_ON__(condition)",
9 | "WARN(condition, format...)": "__replacement__WARN__(condition,format)",
10 | "WARN_TAINT(condition, taint, format...)": "__replacement__WARN_TAINT__(condition,taint,format)",
11 | "WARN_ON_ONCE(condition)": "__replacement__WARN_ON_ONCE__(condition)",
12 | "WARN_ONCE(condition, format...)": "__replacement__WARN_ONCE__(condition,format)",
13 | "WARN_TAINT_ONCE(condition, taint, format...)": "__replacement__WARN_TAINT_ONCE__(condition,taint,format)",
14 | "BUG()": "__replacement__BUG__()",
15 | "barrier()": "__replacement__barrier__()"
16 | }
17 |
--------------------------------------------------------------------------------
/client/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Samsung/CAS/7dcbda6aea35ccd944a4cbc253ccac3788f9bf80/client/__init__.py
--------------------------------------------------------------------------------
/client/exceptions.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class MessageException(Exception):
4 | """
5 | Base class for Exceptions with error message
6 |
7 | :param message: Exception message
8 | :type message: str
9 | """
10 | def __init__(self, message: str):
11 | super(MessageException, self).__init__(message)
12 | self.message = message
13 |
14 | class FilterException(MessageException):
15 | """
16 | Exception object used by `Filter` class
17 |
18 | :param message: Exception message
19 | :type message: str
20 | """
21 |
22 | class ParameterException(MessageException):
23 | """
24 | Exception object used when parameters have errors
25 |
26 | :param message: Exception message
27 | :type message: str
28 | """
29 |
30 | class ArgumentException(MessageException):
31 | """
32 | Exception object used when arguments have errors
33 |
34 | :param message: Exception message
35 | :type message: str
36 | """
37 |
38 | class PipelineException(MessageException):
39 | """
40 | Exception object used when pipeline data does not match
41 |
42 | :param message: Exception message
43 | :type message: str
44 | """
45 |
46 | class LibetraceException(MessageException):
47 | """
48 | Exception object used when libetrace exception occurs
49 |
50 | :param message: Exception message
51 | :type message: str
52 | """
53 |
54 | class LibFtdbException(MessageException):
55 | """
56 | Exception object used when libftdb exception occurs
57 |
58 | :param message: Exception message
59 | :type message: str
60 | """
--------------------------------------------------------------------------------
/client/ftdb_generator/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Samsung/CAS/7dcbda6aea35ccd944a4cbc253ccac3788f9bf80/client/ftdb_generator/__init__.py
--------------------------------------------------------------------------------
/client/ide_generator/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Samsung/CAS/7dcbda6aea35ccd944a4cbc253ccac3788f9bf80/client/ide_generator/__init__.py
--------------------------------------------------------------------------------
/client/misc.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import sys
4 | from typing import Tuple, Dict
5 | from types import ModuleType
6 | from functools import lru_cache
7 |
8 |
9 | @lru_cache(maxsize=1024)
10 | def get_file_info(mode: int) -> Tuple[bool, int, int]:
11 | """
12 | Function split opened file bit value ( 0emmmmxx ) into:
13 | - exist value bit 1
14 | - stat mode bits 2-5
15 | - open mode bits 6-7
16 |
17 | :param mode: bit value
18 | :type mode: int
19 | :return: tuple representing exist, stat_mode, open_mode values
20 | :rtype: tuple
21 | """
22 | exists = True if mode >> 6 & 0b00000001 == 1 else False
23 | stat_mode = mode >> 2 & 0b00001111
24 | open_mode = mode & 0b00000011
25 | # stat_modes = {
26 | # 0x8: "r", # regular file
27 | # 0x4: "d", # directory
28 | # 0x2: "c", # character device
29 | # 0x6: "b", # block device
30 | # 0xa: "l", # symbolic link
31 | # 0x1: "f", # FIFO (named pipe)
32 | # 0xc: "s" # socket
33 | # }
34 | # open_modes = {
35 | # 0x0: "r", # read only
36 | # 0x1: "w", # write only
37 | # 0x2: "rw" # read/write mode
38 | # }
39 | return exists, stat_mode, open_mode
40 |
41 |
42 | @lru_cache(maxsize=1024)
43 | def access_from_code(opn_value) -> str:
44 | """
45 | Function returns string representation of open value(s).
46 | `opn_value` can be single value or list of values.
47 |
48 | :param opn_value: value or values list
49 | :type opn_value: int | list[int]
50 | :return: string representation of open value(s)
51 | :rtype: str
52 | """
53 | if isinstance(opn_value, list):
54 | ret = ''
55 | if 0x0 in opn_value:
56 | ret += 'r'
57 | if 0x1 in opn_value:
58 | ret += 'w'
59 | if 0x2 in opn_value:
60 | return 'rw'
61 | return ret
62 | else:
63 | return {
64 | 0x00: "r", # read only
65 | 0x01: "w", # write only
66 | 0x02: "rw" # read/write mode
67 | }[opn_value]
68 |
69 |
70 | @lru_cache(maxsize=10)
71 | def stat_from_code(stat_value: int) -> str:
72 | """
73 | Function returns string representation of stat value.
74 |
75 | :param stat_value: stat value
76 | :type stat_value: int
77 | :return: string representation of stat value
78 | :rtype: str
79 | """
80 | return {
81 | 0x0: "nonexistent",
82 | 0x8: "file", # regular file
83 | 0x4: "dir", # directory
84 | 0x2: "char", # character device
85 | 0x6: "block", # block device
86 | 0xa: "link", # symbolic link
87 | 0x1: "fifo", # FIFO (named pipe)
88 | 0xc: "sock" # socket
89 | }[stat_value]
90 |
91 |
92 | def fix_cmd(cmd: list, join: bool = True) -> str:
93 | """
94 | Function used to escape special char in command line and returns them in json-friendly version.
95 |
96 | :param cmd: command line to process
97 | :type cmd: list
98 | :param join: specifies if returned command should be joined as single string or preserved as list, defaults to True
99 | :type join: bool, optional
100 | :return: escaped string
101 | :rtype: str
102 | """
103 | if isinstance(cmd, list):
104 | if join:
105 | return json.dumps(" ".join([x.rstrip().replace("\\", "\\\\").replace("\"", "\\\"").replace(" ", "\\ ") for x in cmd]))
106 | else:
107 | return json.dumps([x.rstrip().replace("\\", "\\\\").replace("\"", "\\\"").replace(" ", "\\ ") for x in cmd])
108 | if isinstance(cmd, str):
109 | return json.dumps(cmd.rstrip().replace("\\", "\\\\").replace("\"", "\\\"").replace(" ", "\\ "))
110 |
111 |
112 | def fix_cmd_makefile(cmd: list, static: bool = False) -> str:
113 | """
114 | Function used to escape special char in command line and returns them in makefile-friendly version.
115 |
116 | :param cmd: command line to process
117 | :type cmd: list
118 | :param static: _description_, defaults to False
119 | :type static: bool, optional
120 | :return: escaped string
121 | :rtype: str
122 | """
123 | if static:
124 | return " ".join([x.rstrip().replace("#", "\\#").replace("$", "\\$").replace("(", "\\(").replace(")", "\\)").replace("\"", "\\\"").replace(" ", "\\ ")
125 | if x != "" else "\\\"\\\"" for x in cmd[1:]]) if isinstance(cmd, list) else cmd
126 | else:
127 | return " ".join([x.rstrip().replace("#", "\\#").replace("$", "\\$").replace("(", "\\(").replace(")", "\\)").replace("\"", "\\\"").replace(" ", "\\ ")
128 | if x != "" else "\\\"\\\"" for x in cmd]) if isinstance(cmd, list) else cmd
129 |
130 |
131 | def get_output_renderers() -> Dict[str, ModuleType]:
132 | """
133 | Function check for output renderers and returns map with names and Renderer object.
134 |
135 | :return: map with output name and Renderer object
136 | :rtype: dict
137 | """
138 | ret = dict()
139 | output_renderers_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'output_renderers')
140 | sys.path.append(output_renderers_dir)
141 | for name in os.listdir(output_renderers_dir):
142 | if name.startswith("output_") and name.endswith(".py"):
143 | module_name = name[:-3]
144 | ret[module_name.split("_")[1]] = __import__(module_name)
145 | return ret
146 |
147 |
148 | def get_config_path(config_file: str) -> str:
149 | """
150 | Function attempt to return most probably config path for CASConfig.
151 | Order:
152 | - input file provided from arg
153 | - config from bas/ directory
154 | - config in any of PYTHONPATH dirs
155 |
156 | :param config_file: assumed config file path
157 | :type config_file: str
158 | :return: selected config file path
159 | :rtype: str
160 | """
161 | if os.path.exists(config_file):
162 | return config_file
163 |
164 | # try bas/.bas_config
165 | main_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
166 | if os.path.exists(os.path.join(main_dir, 'bas/.bas_config')):
167 | return os.path.join(main_dir, 'bas/.bas_config')
168 | # try in PYTHONPATH
169 | if "PYTHONPATH" in os.environ:
170 | for pyth_path in os.environ["PYTHONPATH"].split(":"):
171 | if os.path.exists(f"{pyth_path}bas/.bas_config"):
172 | return f"{pyth_path}bas/.bas_config"
173 | assert False, "Config not found!"
174 |
175 |
176 | def printdbg(msg, args, file=sys.stderr, flush=True):
177 | if args.debug:
178 | print(msg, file=file, flush=flush)
179 |
180 |
181 | def printerr(msg, file=sys.stderr, flush=True):
182 | print(msg, file=file, flush=flush)
183 |
184 | def fix_body(body:str) -> str:
185 | return body.replace("\\", "\\\\")\
186 | .replace('"', '\\"')\
187 | .replace("\b", "\\b")\
188 | .replace("\f", "\\f")\
189 | .replace("\n", "\\n")\
190 | .replace("\r", "\\r")\
191 | .replace("\t","\\t")
192 |
--------------------------------------------------------------------------------
/client/mod_executables.py:
--------------------------------------------------------------------------------
1 | from typing import Any, Tuple, Callable
2 | from client.mod_base import Module, PipedModule, FilterableModule
3 | from client.misc import printdbg
4 | from client.output_renderers.output import DataTypes
5 | import libetrace
6 |
7 |
8 | class Binaries(Module, FilterableModule):
9 | """Binaries - returns binaries list or execs that use given binaries."""
10 |
11 | @staticmethod
12 | def get_argparser():
13 | return Module.add_args([
14 | "filter", "command-filter", "select", "append",
15 | "details", "commands"], Binaries)
16 |
17 | def select_subject(self, ent) -> str:
18 | return ent.bpath
19 |
20 | def exclude_subject(self, ent) -> str:
21 | return ent.bpath
22 |
23 | def subject(self, ent) -> "str | libetrace.nfsdbEntryOpenfile":
24 | if self.args.details or self.args.show_commands:
25 | return ent.bpath
26 | else:
27 | return ent
28 |
29 | def prepare_args(self) -> dict:
30 | args: dict = {
31 | "exec_filter": self.command_filter.libetrace_filter if self.command_filter else None,
32 | "has_command": True
33 | }
34 | return args
35 |
36 | def get_data(self) -> Tuple[Any, DataTypes, "Callable | None", "type | None"]:
37 |
38 | args = self.prepare_args()
39 |
40 | if self.args.details or self.args.show_commands:
41 | data = list({e
42 | for e in self.nfsdb.filtered_execs_iter(**args)
43 | if self.should_display_exe(e)
44 | })
45 | return data, DataTypes.commands_data, lambda x: x.bpath, str
46 | else:
47 | data = list({
48 | opn
49 | for opn in self.nfsdb.filtered_paths_iter(file_filter=self.open_filter.libetrace_filter if self.open_filter else None, binary=True)
50 | })
51 |
52 | return data, DataTypes.binary_data, lambda x: x, str
53 |
54 |
55 | class Commands(Module, PipedModule, FilterableModule):
56 | """Commands - returns execs that are commands (bin is not empty)"""
57 |
58 | @staticmethod
59 | def get_argparser():
60 | return Module.add_args([
61 | "filter", "command-filter", "select", "append",
62 | "details", "commands",
63 | "pid", "binary",
64 | "extended",
65 | "parent",
66 | "filerefs", "cdb"], Commands)
67 |
68 | def select_subject(self, ent) -> str:
69 | return " ".join(ent.argv)
70 |
71 | def exclude_subject(self, ent) -> str:
72 | return " ".join(ent.argv)
73 |
74 | def subject(self, ent) -> str:
75 | return " ".join(ent.argv) if not self.args.raw_command else ent.argv
76 |
77 | def set_piped_arg(self, data, data_type: type):
78 | if data_type == str:
79 | printdbg("DEBUG: accepting {} as args.binary".format(data_type), self.args)
80 | self.args.binary = data
81 | elif data_type == libetrace.nfsdbEntryOpenfile:
82 | printdbg("DEBUG: accepting {} as args.binary".format(data_type), self.args)
83 | self.args.binary = list({o.path for o in data})
84 | elif data_type == libetrace.nfsdbEntry:
85 | printdbg("DEBUG: accepting {} as args.binary".format(data_type), self.args)
86 | self.args.binary = list({ex.bpath for ex in data})
87 |
88 | def prepare_args(self) -> dict:
89 | args: dict = {}
90 | if self.command_filter:
91 | args["exec_filter"] = self.command_filter.libetrace_filter
92 | if self.args.generate and not self.args.all:
93 | args["has_comp_info"] = True
94 | else:
95 | args["has_command"] = True
96 | if self.args.binary:
97 | args["bins"] = self.args.binary
98 | if self.args.pid:
99 | args["pids"] = self.args.pid
100 | return args
101 |
102 | def get_data(self) -> Tuple[Any, DataTypes, "Callable | None", "type | None"]:
103 | args = self.prepare_args()
104 | data = self.nfsdb.filtered_execs(**args)
105 |
106 | if self.args.cdb:
107 | data = list(self.cdb_fix_multiple(data))
108 | return data, DataTypes.compilation_db_data, lambda x: x['filename'], str
109 |
110 | return data, DataTypes.commands_data, lambda x: x.argv, libetrace.nfsdbEntry
111 |
112 |
113 | class Execs(Module, PipedModule, FilterableModule):
114 | """Execs - returns all executables"""
115 |
116 | @staticmethod
117 | def get_argparser():
118 | return Module.add_args([
119 | "filter", "command-filter", "select", "append",
120 | "details", "commands",
121 | "pid", "binary",
122 | "extended",
123 | "parent",
124 | "filerefs", "cdb"], Commands)
125 |
126 | def select_subject(self, ent) -> str:
127 | return " ".join(ent.argv)
128 |
129 | def exclude_subject(self, ent) -> str:
130 | return " ".join(ent.argv)
131 |
132 | def subject(self, ent) -> str:
133 | return " ".join(ent.argv) if not self.args.raw_command else ent.argv
134 |
135 | def set_piped_arg(self, data, data_type: type):
136 | if data_type == str:
137 | printdbg("DEBUG: accepting {} as args.binary".format(data_type), self.args)
138 | self.args.binary = data
139 | elif data_type == libetrace.nfsdbEntryOpenfile:
140 | printdbg("DEBUG: accepting {} as args.binary".format(data_type), self.args)
141 | self.args.binary = list({o.path for o in data})
142 | elif data_type == libetrace.nfsdbEntry:
143 | printdbg("DEBUG: accepting {} as args.binary".format(data_type), self.args)
144 | self.args.binary = list({ex.bpath for ex in data})
145 |
146 | def prepare_args(self) -> dict:
147 | args: dict = {}
148 | if self.command_filter:
149 | args["exec_filter"] = self.command_filter.libetrace_filter
150 | if self.args.generate and not self.args.all:
151 | args["has_comp_info"] = True
152 | if self.args.binary:
153 | args["bins"] = self.args.binary
154 | if self.args.pid:
155 | args["pids"] = self.args.pid
156 | return args
157 |
158 | def get_data(self) -> Tuple[Any, DataTypes, Callable, type]:
159 | args = self.prepare_args()
160 | data = self.nfsdb.filtered_execs(**args)
161 |
162 | if self.args.cdb:
163 | data = list(self.cdb_fix_multiple(data))
164 | return data, DataTypes.compilation_db_data, lambda x: x['filename'], str
165 |
166 | return data, DataTypes.commands_data, lambda x: x.argv, libetrace.nfsdbEntry
167 |
--------------------------------------------------------------------------------
/client/mod_funcs.py:
--------------------------------------------------------------------------------
1 | import libftdb
2 | import libft_db
3 | from argparse import ArgumentParser
4 | from typing import Any, Callable, Tuple
5 | from client.mod_base import Module, PipedModule, FilterableModule
6 | from client.output_renderers.output import DataTypes
7 |
8 | class FunctionsModule(Module, FilterableModule, PipedModule):
9 | """ Functions - returns list of functions from Function Type Database """
10 | @staticmethod
11 | def get_argparser() -> ArgumentParser:
12 | return Module.add_args(["ftdb-simple-filter", "details", "body", "ubody"], FunctionsModule)
13 |
14 | def set_piped_arg(self, data, data_type: type) -> None:
15 | if data_type in (libft_db.ftdbSourceEntry, libft_db.ftdbModuleEntry):
16 | self.args.fids = [d.fid for d in data]
17 |
18 | def get_data(self) -> Tuple[Any, DataTypes, "Callable|None", "type|None"]:
19 | if self.has_ftdb_simple_filter:
20 | funcs = [func for func in self.ft_db.get_funcs(getattr(self.args, 'fids', None)) if self.filter_ftdb(func)]
21 | else:
22 | funcs = [func for func in self.ft_db.get_funcs(getattr(self.args, 'fids', None))]
23 | return funcs, DataTypes.function_data, lambda x: x.name, libftdb.ftdbFuncEntry
24 |
25 |
26 | class FuncDeclModule(Module, FilterableModule, PipedModule):
27 | """ Functions - returns list of functions' declarations from Function Type Database """
28 | @staticmethod
29 | def get_argparser() -> ArgumentParser:
30 | return Module.add_args(["ftdb-simple-filter", "details", "declbody"], FuncDeclModule)
31 |
32 | def set_piped_arg(self, data, data_type: type) -> None:
33 | if data_type in (libft_db.ftdbSourceEntry, libft_db.ftdbModuleEntry):
34 | self.args.fids = [d.fid for d in data]
35 |
36 | def get_data(self) -> Tuple[Any, DataTypes, "Callable|None", "type|None"]:
37 | if self.has_ftdb_simple_filter:
38 | funcdecls = [fd for fd in self.ft_db.get_funcdecls(getattr(self.args, 'fids', None)) if self.filter_ftdb(fd)]
39 | else:
40 | funcdecls = [fd for fd in self.ft_db.get_funcdecls(getattr(self.args, 'fids', None))]
41 | return funcdecls, DataTypes.funcdecl_data, lambda x: x.name, libftdb.ftdbFuncdeclEntry
42 |
--------------------------------------------------------------------------------
/client/mod_globals.py:
--------------------------------------------------------------------------------
1 | import libft_db
2 | import libftdb
3 | from argparse import ArgumentParser
4 | from typing import Any, Callable, Tuple
5 | from client.mod_base import Module, PipedModule, FilterableModule
6 | from client.output_renderers.output import DataTypes
7 |
8 | class GlobalsModule(Module, FilterableModule, PipedModule):
9 | """ Globals - returns list of global variables from Function Type Database """
10 | @staticmethod
11 | def get_argparser() -> ArgumentParser:
12 | return Module.add_args(["details", "ftdb-simple-filter", "definition"], GlobalsModule)
13 |
14 | def set_piped_arg(self, data, data_type: type) -> None:
15 | if data_type in (libft_db.ftdbSourceEntry, libft_db.ftdbModuleEntry):
16 | self.args.fids = [d.fid for d in data]
17 |
18 | def get_data(self) -> Tuple[Any, DataTypes, "Callable|None", "type|None"]:
19 | if self.has_ftdb_simple_filter:
20 | globs = [glob for glob in self.ft_db.get_globs(getattr(self.args, 'fids', None)) if self.filter_ftdb(glob)]
21 | else:
22 | globs = [glob for glob in self.ft_db.get_globs(getattr(self.args, 'fids', None))]
23 | return globs, DataTypes.global_data, lambda x: x.name, libftdb.ftdbGlobalEntry
24 |
25 |
26 | class TypesModule(Module, FilterableModule):
27 | """ Types - returns list of types from Function Type Database """
28 | @staticmethod
29 | def get_argparser() -> ArgumentParser:
30 | return Module.add_args(["details", "ftdb-simple-filter"], TypesModule)
31 |
32 | def get_data(self) -> Tuple[Any, DataTypes, "Callable|None", "type|None"]:
33 | if self.has_ftdb_simple_filter:
34 | types = [t for t in self.ft_db.get_types() if self.filter_ftdb(t)]
35 | else:
36 | types = [t for t in self.ft_db.get_types()]
37 | return types, DataTypes.type_data, lambda x: x.name, libftdb.ftdbTypeEntry
38 |
39 |
--------------------------------------------------------------------------------
/client/mod_misc.py:
--------------------------------------------------------------------------------
1 | from client.mod_base import Module
2 | from client.output_renderers.output import DataTypes
3 | from typing import Tuple, Any, Callable
4 |
5 |
6 | class CompilerPattern(Module):
7 | """Compiler Pattern - patterns used to categorize exec as compiler."""
8 |
9 | @staticmethod
10 | def get_argparser():
11 | return Module.add_args([], CompilerPattern)
12 |
13 | def get_data(self) -> tuple:
14 | return {
15 | "armcc_spec": self.config.armcc_spec,
16 | "clang_spec": self.config.clang_spec,
17 | "clangpp_spec": self.config.clangpp_spec,
18 | "gcc_spec": self.config.gcc_spec,
19 | "gpp_spec": self.config.gcc_spec,
20 | }, DataTypes.config_part_data, None, None
21 |
22 |
23 | class LinkerPattern(Module):
24 | """Linker Pattern - patterns used to categorize exec as linker."""
25 |
26 | @staticmethod
27 | def get_argparser():
28 | return Module.add_args([], LinkerPattern)
29 |
30 | def get_data(self) -> tuple:
31 | return {
32 | "ar_spec": self.config.ar_spec,
33 | "ld_spec": self.config.ld_spec
34 | }, DataTypes.config_part_data, None, None
35 |
36 |
37 | class VersionInfo(Module):
38 | """Version info - prints version meta information (set in 'cas cache' step)."""
39 |
40 | @staticmethod
41 | def get_argparser():
42 | return Module.add_args([], VersionInfo)
43 |
44 | def get_data(self) -> tuple:
45 | return self.nfsdb.get_version(), DataTypes.dbversion_data, None, None
46 |
47 |
48 | class RootPid(Module):
49 | """Root pid - prints pid of first process that was started during tracing."""
50 |
51 | @staticmethod
52 | def get_argparser():
53 | return Module.add_args([], RootPid)
54 |
55 | def get_data(self) -> tuple:
56 | return self.nfsdb.db[0].eid.pid, DataTypes.root_pid_data, None, None
57 |
58 |
59 | class SourceRoot(Module):
60 | """Source root - prints directory where first process started work (set in 'cas parse' step)."""
61 |
62 | @staticmethod
63 | def get_argparser():
64 | return Module.add_args([], SourceRoot)
65 |
66 | def get_data(self) -> tuple:
67 | return self.source_root, DataTypes.source_root_data, None, None
68 |
69 |
70 | class ShowConfig(Module):
71 | """Show config - prints parsed config."""
72 |
73 | @staticmethod
74 | def get_argparser():
75 | return Module.add_args([], ShowConfig)
76 |
77 | def get_data(self) -> tuple:
78 | return self.config, DataTypes.config_data, None, None
79 |
80 |
81 | class ShowStat(Module):
82 | """Show statistics - prints database statistics."""
83 |
84 | @staticmethod
85 | def get_argparser():
86 | return Module.add_args([], ShowStat)
87 |
88 | def get_data(self) -> tuple:
89 | return {
90 | "execs": self.nfsdb.execs_num(),
91 | "execs_commands": len(self.nfsdb.db.filtered_execs_iter(has_command=True)),
92 | "execs_compilations": len(self.nfsdb.db.filtered_execs_iter(has_comp_info=True)),
93 | "execs_linking": len(self.nfsdb.db.filtered_execs_iter(has_linked_file=True)),
94 | "binaries": len(self.nfsdb.db.binary_paths()),
95 | "opens": self.nfsdb.opens_num(),
96 | "linked": len(self.nfsdb.get_linked_files()),
97 | "compiled": len(self.nfsdb.get_compiled_files()),
98 | "compiled_paths": len(self.nfsdb.get_compiled_file_paths()),
99 | "linked_paths": len(self.nfsdb.get_linked_file_paths())
100 | }, DataTypes.stat_data, None, None
101 |
102 |
103 | class FtdbVersion(Module):
104 | """ Ftdb Version - show Function Type Database version """
105 | @staticmethod
106 | def get_argparser():
107 | return Module.add_args([], FtdbVersion)
108 |
109 | def get_data(self) -> Tuple[Any, DataTypes, "Callable|None", "type|None"]:
110 | return self.ft_db.get_version(), DataTypes.dbversion_data, None, None
111 |
112 |
113 | class FtdbModuleName(Module):
114 | """ Ftdb Module Name - show FTDB module name """
115 | @staticmethod
116 | def get_argparser():
117 | return Module.add_args([], FtdbModuleName)
118 |
119 | def get_data(self) -> Tuple[Any, DataTypes, "Callable|None", "type|None"]:
120 | return self.ft_db.get_module_name(), DataTypes.module_name_data, None, None
121 |
122 |
123 | class FtdbDirectoryName(Module):
124 | """ Ftdb Directory Name - show base directiory of FTDB"""
125 | @staticmethod
126 | def get_argparser():
127 | return Module.add_args([], FtdbDirectoryName)
128 |
129 | def get_data(self) -> Tuple[Any, DataTypes, "Callable|None", "type|None"]:
130 | return self.ft_db.get_dir(), DataTypes.dir_name_data, None, None
131 |
132 |
133 | class FtdbReleaseName(Module):
134 | """ Ftdb Release Name - show release name of FTDB """
135 | @staticmethod
136 | def get_argparser():
137 | return Module.add_args([], FtdbReleaseName)
138 |
139 | def get_data(self) -> Tuple[Any, DataTypes, "Callable|None", "type|None"]:
140 | return self.ft_db.get_release(), DataTypes.release_name_data, None, None
141 |
142 |
--------------------------------------------------------------------------------
/client/mod_sources.py:
--------------------------------------------------------------------------------
1 | import libftdb
2 | import libft_db
3 | from argparse import ArgumentParser
4 | from client.mod_base import Module, FilterableModule, PipedModule
5 | from client.output_renderers.output import DataTypes
6 | from client.misc import printdbg
7 | from typing import List, Tuple, Any, Callable
8 |
9 |
10 | class SourcesModule(Module, FilterableModule, PipedModule):
11 | """
12 | Sources from FTDatabase
13 | """
14 | @staticmethod
15 | def get_argparser():
16 | return Module.add_args(["details", "ftdb-simple-filter"], SourcesModule)
17 |
18 | def set_piped_arg(self, data, data_type: type) -> None:
19 | if type(data[0]).__name__ == 'ftdbFuncEntry':
20 | printdbg(f"DEBUG: accepting type {data_type}", self.args)
21 | fids = set()
22 | for d in data:
23 | fids = fids.union(set(d.fids))
24 | self.args.fids = fids
25 | elif type(data[0]).__name__ == 'ftdbFuncdeclEntry' or type(data[0]).__name__ == 'ftdbGlobalEntry':
26 | self.args.fids = list(set([fd.fid for fd in data]))
27 |
28 | def get_data(self) -> Tuple[Any, DataTypes, "Callable|None", "type|None"]:
29 | if self.has_ftdb_simple_filter:
30 | srcs: List[libft_db.ftdbSourceEntry] = [src
31 | for src in self.ft_db.get_sources(getattr(self.args, 'fids', None))
32 | if self.filter_ftdb(src)]
33 | else:
34 | srcs: List[libft_db.ftdbSourceEntry] = [src for src in self.ft_db.get_sources(getattr(self.args, 'fids', None))]
35 | return srcs, DataTypes.sources_data, None, libft_db.ftdbSourceEntry
36 |
37 | class FTModules(Module, FilterableModule, PipedModule):
38 | """
39 | Modules from FTDatabase
40 | """
41 |
42 | @staticmethod
43 | def get_argparser() -> ArgumentParser:
44 | return Module.add_args(["details", "ftdb-simple-filter"], FTModules)
45 |
46 | def set_piped_arg(self, data, data_type: type) -> None:
47 | if type(data[0]).__name__ in ('ftdbFuncEntry', 'ftdbGlobalEntry'):
48 | printdbg(f"DEBUG: accepting type {data_type}", self.args)
49 | mids = set()
50 | for d in data:
51 | mids = mids.union(set(d.mids))
52 | self.args.mids = mids
53 |
54 | def get_data(self) -> Tuple[Any, DataTypes, "Callable|None", "type|None"]:
55 | if self.has_ftdb_simple_filter:
56 | mds: List[Tuple[int,str]] = [md for md in self.ft_db.get_modules(getattr(self.args, 'mids', None)) if self.filter_ftdb(md)]
57 | else:
58 | mds: List[Tuple[int,str]] = [md for md in self.ft_db.get_modules(getattr(self.args, 'mids', None))]
59 | return mds, DataTypes.modules_data, None, libft_db.ftdbModuleEntry
60 |
--------------------------------------------------------------------------------
/client/output_renderers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Samsung/CAS/7dcbda6aea35ccd944a4cbc253ccac3788f9bf80/client/output_renderers/__init__.py
--------------------------------------------------------------------------------
/client/static/deps_modal.js:
--------------------------------------------------------------------------------
1 | let fileModal = document.getElementById('proc_info_modal')
2 |
3 | function nextFiles(maxResults=50) {
4 | let deps_div = fileModal.querySelector('.module_filename');
5 | let opens_div = fileModal.querySelector('.file_contents');
6 | let files_pages = fileModal.querySelector('.files_page_numbers');
7 | let page = parseInt(files_pages.innerText.split("/")[0]) - 1;
8 | if (page < (parseInt(files_pages.innerText.split("/")[1]) - 1)) {
9 | page++;
10 | let request = '/deps_for?path=' + deps_div.innerText +"&page=" + page+'&entries-per-page='+maxResults+'&cached=true';
11 | $.get(request, function (data) {
12 | Array.from(opens_div.getElementsByTagName("p")).forEach(element => {
13 | element.remove();
14 | });
15 | for (d in data["entries"]) {
16 | opens_div.innerHTML += "" + data["entries"][d] + "
"
17 | }
18 | files_pages.innerText = (page + 1) + "/" + Math.ceil(data.count/maxResults).toString()
19 | if (page > 0) {
20 | fileModal.querySelector('#prevFilesButton').removeAttribute('disabled');
21 | }
22 | if (page === parseInt(files_pages.innerText.split("/")[1]) - 1) {
23 | fileModal.querySelector('#nextFilesButton').setAttribute('disabled', '');
24 | }
25 | });
26 | }
27 | }
28 |
29 | function prevFiles(maxResults=50) {
30 | let deps_div = fileModal.querySelector('.module_filename');
31 | let opens_div = fileModal.querySelector('.file_contents');
32 | let files_pages = fileModal.querySelector('.files_page_numbers');
33 | let page = parseInt(files_pages.innerText.split("/")[0]) - 1;
34 | if (page > 0) {
35 | page--;
36 | let request = '/deps_for?path=' + deps_div.innerText +"&page=" + page+'&entries-per-page='+maxResults+'&cached=true';
37 | $.get(request, function (data) {
38 | Array.from(opens_div.getElementsByTagName("p")).forEach(element => {
39 | element.remove();
40 | });
41 | for (d in data["entries"]) {
42 | opens_div.innerHTML += "" + data["entries"][d] + "
"
43 | }
44 | files_pages.innerText = (page + 1) + "/" + Math.ceil(data.count/maxResults).toString()
45 | if (page === 0) {
46 | fileModal.querySelector('#prevFilesButton').setAttribute('disabled', '');
47 | }
48 | if (page < parseInt(files_pages.innerText.split("/")[1]) - 1) {
49 | fileModal.querySelector('#nextFilesButton').removeAttribute('disabled');
50 | }
51 | });
52 | }
53 | }
54 |
55 | fileModal.addEventListener('show.bs.modal', function (event) {
56 | let page = 0;
57 | let button = event.relatedTarget
58 | let deps_path = button.getAttribute('data-bs-pid')
59 | let maxResults=50
60 | let modalTitle = fileModal.querySelector('.modal-title')
61 | modalTitle.textContent = 'Dependencies of: ' + deps_path
62 | let opens_div = fileModal.querySelector('.file_contents')
63 | let filename = fileModal.querySelector('.module_filename')
64 | let original_path = fileModal.querySelector('.module_path')
65 | let ppid = fileModal.querySelector('.module_parent')
66 | let type = fileModal.querySelector('.module_type')
67 | let access = fileModal.querySelector('.module_access')
68 | let exists = fileModal.querySelector('.module_exists')
69 | let link = fileModal.querySelector('.module_link')
70 | let files_pages = fileModal.querySelector('.files_page_numbers')
71 | fileModal.querySelector('#prevFilesButton').setAttribute('disabled', '');
72 | fileModal.querySelector('#nextFilesButton').removeAttribute('disabled');
73 | let request = '/linked_modules?filter=[path='+deps_path+']&details=true';
74 | $.get(request, function (data) {
75 | let entry = data.entries[0];
76 | filename.innerText = entry.filename;
77 | original_path.innerText = entry.original_path;
78 | ppid.innerHTML = "'+entry.ppid+"";
79 | type.innerText = entry.type;
80 | access.innerText = entry.access;
81 | exists.innerText = entry.exists;
82 | link.innerText = entry.link;
83 | });
84 | request = '/deps_for?path=' + deps_path + "&page=" + page + '&entries-per-page='+maxResults+'&cached=true';
85 | $.get(request, function (data) {
86 | if (Math.ceil(data.count/maxResults) < 2) {
87 | fileModal.querySelector('#nextFilesButton').setAttribute('disabled', '');
88 | }
89 | files_pages.innerText = (page + 1).toString() + "/" + Math.ceil(data.count/maxResults).toString()
90 | opens_div.innerHTML = ""
91 | if (data["entries"].length > 0 ){
92 | if(fileModal.querySelector('#headingFiles').children[0].classList.contains("collapsed")){
93 | fileModal.querySelector('#headingFiles').children[0].click();
94 | }
95 | fileModal.querySelector('#openModal').style.display = "block";
96 | }
97 | for (d in data["entries"]) {
98 | opens_div.innerHTML += "" + data["entries"][d] + "
"
99 | }
100 | });
101 | })
102 | fileModal.addEventListener('hidden.bs.modal', function (event) {
103 | fileModal.querySelector('#openModal').style.display = "none";
104 | fileModal.querySelector('.file_contents').innerHTML = "";
105 | })
--------------------------------------------------------------------------------
/client/static/revdeps_modal.js:
--------------------------------------------------------------------------------
1 | let fileModal = document.getElementById('proc_info_modal')
2 |
3 | function nextFiles(maxResults=50) {
4 | let modalTitle = fileModal.querySelector('.modal-title');
5 | let opens_div = fileModal.querySelector('.file_contents');
6 | let files_pages = fileModal.querySelector('.files_page_numbers');
7 | let page = parseInt(files_pages.innerText.split("/")[0]) - 1;
8 | if (page < (parseInt(files_pages.innerText.split("/")[1]) - 1)) {
9 | page++;
10 | let request = '/revdeps_for?path=' + modalTitle.getAttribute("data-path") +"&page=" + page+'&entries-per-page='+maxResults+ "&recursive=true&relative=true&sorted=true";
11 | $.get(request, function (data) {
12 | Array.from(opens_div.getElementsByTagName("p")).forEach(element => {
13 | element.remove();
14 | });
15 | for (d in data["entries"]) {
16 | opens_div.innerHTML += "" + data["entries"][d] + "
"
17 | }
18 | files_pages.innerText = (page + 1) + "/" + Math.ceil(data.count/maxResults).toString()
19 | if (page > 0) {
20 | fileModal.querySelector('#prevFilesButton').removeAttribute('disabled');
21 | }
22 | if (page === parseInt(files_pages.innerText.split("/")[1]) - 1) {
23 | fileModal.querySelector('#nextFilesButton').setAttribute('disabled', '');
24 | }
25 | });
26 | }
27 | }
28 |
29 | function prevFiles(maxResults=50) {
30 | let modalTitle = fileModal.querySelector('.modal-title');
31 | let opens_div = fileModal.querySelector('.file_contents');
32 | let files_pages = fileModal.querySelector('.files_page_numbers');
33 | let page = parseInt(files_pages.innerText.split("/")[0]) - 1;
34 | if (page > 0) {
35 | page--;
36 | let request = '/revdeps_for?path=' + modalTitle.getAttribute("data-path") +"&page=" + page+'&entries-per-page='+maxResults+ "&recursive=true&relative=true&sorted=true";
37 | $.get(request, function (data) {
38 | Array.from(opens_div.getElementsByTagName("p")).forEach(element => {
39 | element.remove();
40 | });
41 | for (d in data["entries"]) {
42 | opens_div.innerHTML += "" + data["entries"][d] + "
"
43 | }
44 | files_pages.innerText = (page + 1) + "/" + Math.ceil(data.count/maxResults).toString()
45 | if (page === 0) {
46 | fileModal.querySelector('#prevFilesButton').setAttribute('disabled', '');
47 | }
48 | if (page < parseInt(files_pages.innerText.split("/")[1]) - 1) {
49 | fileModal.querySelector('#nextFilesButton').removeAttribute('disabled');
50 | }
51 | });
52 | }
53 | }
54 |
55 | fileModal.addEventListener('show.bs.modal', function (event) {
56 | let page = 0;
57 | let button = event.relatedTarget;
58 | let deps_path = button.getAttribute('data-bs-path');
59 | let maxResults=50
60 | let modalTitle = fileModal.querySelector('.modal-title');
61 | modalTitle.textContent = 'Reversed dependencies of: ' + deps_path
62 | modalTitle.setAttribute('data-path', deps_path);
63 | let opens_div = fileModal.querySelector('.file_contents')
64 | let filename = fileModal.querySelector('.module_filename')
65 | let original_path = fileModal.querySelector('.module_path')
66 | let ppid = fileModal.querySelector('.module_parent')
67 | let type = fileModal.querySelector('.module_type')
68 | let access = fileModal.querySelector('.module_access')
69 | let exists = fileModal.querySelector('.module_exists')
70 | let link = fileModal.querySelector('.module_link')
71 | let files_pages = fileModal.querySelector('.files_page_numbers')
72 | fileModal.querySelector('#prevFilesButton').setAttribute('disabled', '');
73 | fileModal.querySelector('#nextFilesButton').removeAttribute('disabled');
74 | let request = '/linked_modules?filter=[path='+deps_path+']&details=true';
75 | filename.innerText = "";
76 | original_path.innerText = "";
77 | ppid.innerHTML = "";
78 | type.innerText = "";
79 | access.innerText = "";
80 | exists.innerText = "";
81 | link.innerText = "";
82 | $.get(request, function (data) {
83 | let entry = data.entries[0];
84 | if(data.entries.length < 1)
85 | {
86 | fileModal.querySelector('.process_details').setAttribute('hidden', '');
87 | }
88 | else{
89 | fileModal.querySelector('.process_details').removeAttribute('hidden');
90 | }
91 | filename.innerText = entry.filename;
92 | original_path.innerText = entry.original_path;
93 | ppid.innerHTML = "'+entry.ppid+"";
94 | type.innerText = entry.type;
95 | access.innerText = entry.access;
96 | exists.innerText = entry.exists;
97 | link.innerText = entry.link;
98 | });
99 | request = '/revdeps_for?path=' + deps_path + "&page=" + page + '&entries-per-page='+maxResults+ "&recursive=true&relative=true&sorted=true";
100 | $.get(request, function (data) {
101 | if (Math.ceil(data.count/maxResults) < 2) {
102 | fileModal.querySelector('#nextFilesButton').setAttribute('disabled', '');
103 | }
104 | files_pages.innerText = (page + 1).toString() + "/" + Math.ceil(data.count/maxResults).toString()
105 | opens_div.innerHTML = ""
106 | if (data["entries"].length > 0 ){
107 | if(fileModal.querySelector('#headingFiles').children[0].classList.contains("collapsed")){
108 | fileModal.querySelector('#headingFiles').children[0].click();
109 | }
110 | fileModal.querySelector('#openModal').style.display = "block";
111 | }
112 | for (d in data["entries"]) {
113 | opens_div.innerHTML += "" + data["entries"][d] + "
"
114 | }
115 | });
116 | })
117 | fileModal.addEventListener('hidden.bs.modal', function (event) {
118 | fileModal.querySelector('#openModal').style.display = "none";
119 | fileModal.querySelector('.file_contents').innerHTML = "";
120 | })
--------------------------------------------------------------------------------
/client/static/style.css:
--------------------------------------------------------------------------------
1 | .file_mode_r{
2 | margin:0px;
3 | font-size: small;
4 | }
5 | .file_mode_rw{
6 | color:orange;
7 | margin:0px;
8 | font-size: small;
9 | }
10 | .file_mode_w{
11 | color:red;
12 | margin:0px;
13 | font-size: small;
14 | }
15 |
16 | .sticky{
17 | position: sticky;
18 | top: 0;
19 | z-index: 1;
20 | }
21 |
22 | .tree li button.pid {
23 | width: 220px !important;
24 | }
25 |
26 | .tree li.page-item::before {
27 | display: none;
28 | }
29 | .tree li.page-item::after {
30 | display: none;
31 | }
32 |
33 | .tree ul {
34 | list-style: none;
35 | }
36 |
37 | .tree ul li {
38 | padding:10px 0 0 0;
39 | position: relative;
40 | }
41 | .tree>ul>li>ul {
42 | padding-left: 15px;
43 | }
44 |
45 | .tree ul li:before,
46 | .tree ul li ul li:before {
47 | content: "";
48 | position: absolute;
49 | top: 0px;
50 | left: -10px;
51 | border-left: 1px solid #999;
52 | width: 1px;
53 | height: 100%;
54 | }
55 |
56 | .tree ul li:after,
57 | .tree ul li ul li:after {
58 | content: "";
59 | position: absolute;
60 | border-top: 1px solid #999;
61 | top: 25px;
62 | left: -10px;
63 | width: 10px;
64 | }
65 |
66 | .tree ul li:last-child:before {
67 | top: 0px;
68 | height: 25px;
69 | }
70 |
71 | .tree>ul>li:after,
72 | .tree>ul>li:last-child:before {
73 | content: unset;
74 | }
75 |
76 | .tree li span {
77 | display:inline-block;
78 | height: fit-content;
79 | }
80 |
81 | .tree li span.bin {
82 | font-weight: bold;
83 | }
84 |
85 | .tree li button.pid span.open_len{
86 | float:right;
87 | }
88 |
89 | .tree li button.pid span.child_len{
90 | float:left;
91 | }
92 | .tree li span.etime{
93 | min-width:100px;
94 | max-width:100px;
95 | text-align: center;
96 | }
97 |
98 | .linker{
99 | background-color:yellow;
100 | }
101 | .compiler{
102 | background-color:lightgreen;
103 | }
104 |
105 | .advanced-form{
106 | padding: 10px;
107 | margin-left: 30px;
108 | }
109 |
110 | #searchNumbers{
111 | padding: 10px;
112 | margin-left: 50px;
113 | }
114 |
115 | .classLabel{
116 | margin-right: 15px;
117 | margin-top: 6px;
118 | }
119 |
120 | .upper_parent{
121 | cursor: pointer;
122 | text-decoration: none;
123 | position:absolute;
124 | left:-20px;
125 | }
126 | span.col-md-auto{
127 | padding: 13px;
128 | }
129 | ul.pagination{
130 | padding: 10px;
131 | }
132 |
133 | div.row{
134 | padding: 10px;
135 | }
--------------------------------------------------------------------------------
/client/templates/deps_tree.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 | {% block title %}Dependencies Tree{% endblock %}
3 | {% block head %}
4 | {{ super() }}
5 |
6 |
7 | {% endblock %}
8 | {% block content %}
9 |
10 |
11 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
37 |
38 |
Module details
39 |
40 |
43 |
46 |
47 |
PPID:
48 |
Type:
49 |
Access:
50 |
Exists:
51 |
Link:
52 |
53 |
54 |
55 |
56 |
57 |
62 |
63 |
64 |
65 |
66 |
Page 1/1
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
77 |
78 |
79 |
80 |
81 |
82 | {% if exe and exe["count"] > exe["num_entries"] %}
83 |
86 | {% endif %}
87 |
88 |
89 |
90 | {%for i in range(0, exe['num_entries'])%}
91 | -
92 |
93 |
101 |
102 |
{{exe['entries'][i]['path']}}
103 |
104 | ^
105 |
106 |
107 |
108 | {%endfor%}
109 |
110 |
111 |
112 | {% endblock %}
--------------------------------------------------------------------------------
/client/templates/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {% block head %}
4 | {% block title %}{% endblock %}
5 |
6 |
7 |
8 | {% endblock %}
9 |
10 |
11 |
12 | {% block content %}
13 | {% endblock %}
14 |
15 |
19 |
20 |
--------------------------------------------------------------------------------
/client/templates/revdeps_tree.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 | {% block title %}Reversed Dependencies Tree{% endblock %}
3 | {% block head %}
4 | {{ super() }}
5 |
6 |
7 | {% endblock %}
8 | {% block content %}
9 |
10 |
11 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
37 |
38 |
Module details
39 |
40 |
43 |
46 |
47 |
PPID:
48 |
Type:
49 |
Access:
50 |
Exists:
51 |
Link:
52 |
53 |
54 |
55 |
56 |
57 |
62 |
63 |
64 |
65 |
66 |
Page 1/1
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
77 |
78 |
79 |
80 |
81 |
82 | {% if exe and exe["count"] > exe["num_entries"] %}
83 |
86 | {% endif %}
87 |
88 |
89 |
90 | {%for i in range(0, exe['num_entries'])%}
91 | -
92 |
93 |
103 |
104 |
{{exe['entries'][i]['path']}}
105 |
106 | ^
107 |
108 |
109 |
110 | {%endfor%}
111 |
112 |
113 |
114 | {% endblock %}
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = source
9 | BUILDDIR = build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=source
11 | set BUILDDIR=build
12 |
13 | %SPHINXBUILD% >NUL 2>NUL
14 | if errorlevel 9009 (
15 | echo.
16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
17 | echo.installed, then set the SPHINXBUILD environment variable to point
18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
19 | echo.may add the Sphinx directory to PATH.
20 | echo.
21 | echo.If you don't have Sphinx installed, grab it from
22 | echo.https://www.sphinx-doc.org/
23 | exit /b 1
24 | )
25 |
26 | if "%1" == "" goto help
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/docs/source/client.rst:
--------------------------------------------------------------------------------
1 | CAS client
2 | ==========
3 |
4 | client.argparser module
5 | -----------------------
6 |
7 | .. automodule:: client.argparser
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
12 | client.cmdline module
13 | ---------------------
14 |
15 | .. automodule:: client.cmdline
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | client.filtering module
21 | -----------------------
22 |
23 | .. automodule:: client.filtering
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | client.ide\_generator module
29 | ----------------------------
30 |
31 | .. automodule:: client.ide_generator
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 | client.misc module
37 | ------------------
38 |
39 | .. automodule:: client.misc
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 | client.mod\_base module
45 | -----------------------
46 |
47 | .. automodule:: client.mod_base
48 | :members:
49 | :undoc-members:
50 | :show-inheritance:
51 |
52 | client.mod\_compilation module
53 | ------------------------------
54 |
55 | .. automodule:: client.mod_compilation
56 | :members:
57 | :undoc-members:
58 | :show-inheritance:
59 |
60 | client.mod\_dbops module
61 | ------------------------
62 |
63 | .. automodule:: client.mod_dbops
64 | :members:
65 | :undoc-members:
66 | :show-inheritance:
67 |
68 | client.mod\_dependencies module
69 | -------------------------------
70 |
71 | .. automodule:: client.mod_dependencies
72 | :members:
73 | :undoc-members:
74 | :show-inheritance:
75 |
76 | client.mod\_executables module
77 | ------------------------------
78 |
79 | .. automodule:: client.mod_executables
80 | :members:
81 | :undoc-members:
82 | :show-inheritance:
83 |
84 | client.mod\_modules module
85 | ----------------------------------
86 |
87 | .. automodule:: client.mod_modules
88 | :members:
89 | :undoc-members:
90 | :show-inheritance:
91 |
92 | client.mod\_misc module
93 | -----------------------
94 |
95 | .. automodule:: client.mod_misc
96 | :members:
97 | :undoc-members:
98 | :show-inheritance:
99 |
100 | client.mod\_opened\_files module
101 | --------------------------------
102 |
103 | .. automodule:: client.mod_opened_files
104 | :members:
105 | :undoc-members:
106 | :show-inheritance:
107 |
108 | client.output\_renderers.output module
109 | --------------------------------------
110 |
111 | .. automodule:: client.output_renderers.output
112 | :members:
113 | :undoc-members:
114 | :show-inheritance:
115 |
116 | client.output\_renderers.output\_plain module
117 | ---------------------------------------------
118 |
119 | .. automodule:: client.output_renderers.output_plain
120 | :members:
121 | :undoc-members:
122 | :show-inheritance:
123 |
124 | client.output\_renderers.output\_json module
125 | --------------------------------------------
126 |
127 | .. automodule:: client.output_renderers.output_json
128 | :members:
129 | :undoc-members:
130 | :show-inheritance:
131 |
--------------------------------------------------------------------------------
/docs/source/conf.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 |
4 | project = 'CAS'
5 | copyright = '2022, a.niec@samsung.com'
6 | author = 'a.niec@samsung.com'
7 | release = '1.0'
8 |
9 | extensions = ['sphinx.ext.autodoc']
10 |
11 | templates_path = ['_templates']
12 | exclude_patterns = ['test_main.py']
13 |
14 | html_theme = 'sphinx_rtd_theme'
15 | html_static_path = ['_static']
16 |
17 | sys.path.insert(0, os.path.abspath('../..'))
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. CAS Client documentation master file, created by
2 | sphinx-quickstart on Thu Nov 17 12:28:29 2022.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to CAS documentation!
7 | =============================
8 |
9 | .. toctree::
10 | :maxdepth: 4
11 | :caption: Contents:
12 |
13 | client
14 | libcas
15 |
16 | Indices and tables
17 | ==================
18 |
19 | * :ref:`genindex`
20 | * :ref:`modindex`
21 | * :ref:`search`
22 |
--------------------------------------------------------------------------------
/docs/source/libcas.rst:
--------------------------------------------------------------------------------
1 | CAS library
2 | ===========
3 |
4 | libcas module
5 | -------------
6 |
7 | .. automodule:: libcas
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
--------------------------------------------------------------------------------
/etrace:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Run syscalls tracing of a given command
4 | # Usage:
5 | # etrace COMMAND ...
6 |
7 | print_usage () {
8 | echo "Usage: etrace [-hlimte] [-w WORK_DIR] [--] COMMAND ..."
9 | }
10 |
11 | echo_err () {
12 | echo "[!] $1"
13 | }
14 |
15 | if [ "$#" -lt 1 ]; then
16 | print_usage
17 | exit 1
18 | fi
19 |
20 | # -------- parse args
21 | SAVE_KERNEL_LOG=
22 | WORK_DIR=$(pwd)
23 | INITCWD=$(pwd)
24 | MODULE_PARAMS=""
25 |
26 | while getopts "hilmtew:" opt; do
27 | case "$opt" in
28 | h)
29 | print_usage
30 | exit 0
31 | ;;
32 | l)
33 | SAVE_KERNEL_LOG=y
34 | ;;
35 | w)
36 | WORK_DIR="$OPTARG"
37 | mkdir -p "$WORK_DIR"
38 | ;;
39 | i)
40 | MODULE_PARAMS="$MODULE_PARAMS ignore_repeated_opens=1"
41 | ;;
42 | t)
43 | MODULE_PARAMS="$MODULE_PARAMS trace_thread_names=1"
44 | ;;
45 | m)
46 | MODULE_PARAMS="$MODULE_PARAMS enable_mount=1"
47 | ;;
48 | e)
49 | MODULE_PARAMS="$MODULE_PARAMS trace_env_vars=1"
50 | ;;
51 | esac
52 | done
53 |
54 | # Remove script's arguments so that "$@" contains the command to run
55 | # under tracer
56 | shift $((OPTIND-1))
57 | # If arguments were separated from the command by "--", remove it too
58 | [ "${1:-}" = "--" ] && shift
59 |
60 |
61 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
62 | NPROC=$(nproc)
63 | NPROC=$(expr $NPROC - 1)
64 |
65 | # -------- setting up ftrace
66 | if (( $EUID != 0 )); then
67 | sudo -n setup_etrace.sh -f
68 | else
69 | setup_etrace.sh -f
70 | fi
71 | if [ "$?" -ne 0 ]; then
72 | echo_err "setup_etrace.sh -f failed"
73 | exit 1
74 | fi
75 |
76 | # -------- save our CWD
77 | echo "INITCWD=$INITCWD" > "$WORK_DIR/.nfsdb"
78 |
79 | # -------- set up event listener
80 | #${DIR}/etrace_cat "/sys/kernel/debug/tracing/trace_pipe" > "$WORK_DIR/.nfsdb" &
81 | ${DIR}/cati "/sys/kernel/debug/tracing/trace_pipe" >> "$WORK_DIR/.nfsdb" &
82 | LISTENER_PID="$!"
83 | if (( $EUID != 0 )); then
84 | sudo -n renice -n -18 -p $LISTENER_PID >/dev/null 2>&1
85 | else
86 | renice -n -18 -p $LISTENER_PID >/dev/null 2>&1
87 | fi
88 | # -------- save kernel log
89 | if [ "$SAVE_KERNEL_LOG" = "y" ]; then
90 | dmesg -w > "$WORK_DIR/.nfsdb.klog" &
91 | KLOGGER_PID="$!"
92 | fi
93 |
94 | # -------- install bas_tracer module
95 | MYPID="$$"
96 | if (( $EUID != 0 )); then
97 | sudo -n setup_etrace.sh -i $MYPID $MODULE_PARAMS
98 | else
99 | setup_etrace.sh -i $MYPID $MODULE_PARAMS
100 | fi
101 | if [ "$?" -ne 0 ]; then
102 | echo_err "setup_etrace.sh -i failed"
103 | exit 1
104 | fi
105 |
106 | # -------- run the command
107 | "$@"
108 | RV="$?"
109 |
110 | # -------- remove bas_tracer module
111 | if (( $EUID != 0 )); then
112 | sudo -n setup_etrace.sh -r
113 | else
114 | setup_etrace.sh -r
115 | fi
116 | if [ "$?" -ne 0 ]; then
117 | echo_err "setup_etrace.sh -r failed"
118 | exit 1
119 | fi
120 |
121 | # Save stat information to see if any events have been missing
122 | rm -f "$WORK_DIR/.nfsdb.stats" && touch "$WORK_DIR/.nfsdb.stats"
123 | for i in `seq 0 $NPROC`; do
124 | echo "##---------- CPU $i ---------- ##" >> "$WORK_DIR/.nfsdb.stats"
125 | cat "/sys/kernel/debug/tracing/per_cpu/cpu$i/stats" >> "$WORK_DIR/.nfsdb.stats"
126 | done
127 |
128 | # -------- stop event listener
129 | if [ -f "${WORK_DIR}/.nfsdb" ]; then
130 | PREV_LINE=`tail -n 1 ${WORK_DIR}/.nfsdb`
131 | sleep 2
132 | CURR_LINE=`tail -n 1 ${WORK_DIR}/.nfsdb`
133 | while [ "${PREV_LINE}" != "${CURR_LINE}" ]; do
134 | PREV_LINE=${CURR_LINE}
135 | sleep 2
136 | CURR_LINE=`tail -n 1 ${WORK_DIR}/.nfsdb`
137 | done
138 | fi
139 |
140 | kill -SIGINT "${LISTENER_PID}"
141 |
142 | # -------- stop kernel logger
143 | if [ "$SAVE_KERNEL_LOG" = "y" ]; then
144 | kill -SIGINT "${KLOGGER_PID}"
145 | fi
146 |
147 | # We're done here
148 | exit $RV
149 |
--------------------------------------------------------------------------------
/etrace_install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cp -f setup_etrace.sh /usr/bin/setup_etrace.sh
4 | chown root:root /usr/bin/setup_etrace.sh
5 | chmod 755 /usr/bin/setup_etrace.sh
6 | if [ -d /etc/sudoers.d/ ]; then
7 | cp -f etrace_sudoers /etc/sudoers.d/etrace
8 | chmod 440 /etc/sudoers.d/etrace
9 | fi
10 |
11 | echo "The following entry has been added to the '/etc/sudoers.d/etrace' file"
12 | echo " ALL ALL = (root) NOPASSWD: /usr/bin/setup_etrace.sh"
13 | echo "This should allow to run the etrace command for any user without sudo password"
14 | echo "In case of problems please make sure the following line is located at the end of the '/etc/sudoers' file"
15 | echo " #includedir /etc/sudoers.d"
16 | echo
--------------------------------------------------------------------------------
/etrace_sudoers:
--------------------------------------------------------------------------------
1 | # Allow to use kernel tracing technology for etrace command for any user
2 | Defaults env_keep += "TRACING_BUFF_SIZE_KB"
3 | ALL ALL = (root) NOPASSWD: /usr/bin/setup_etrace.sh
4 |
--------------------------------------------------------------------------------
/examples/build-avdkernel.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # You would need to install clang-11 based toolchain (including ld.lld-11) to make this example working (or modify this example accordingly)
4 |
5 | export ROOT_DIR=$(pwd)
6 | export KERNEL_DIR=$ROOT_DIR/kernel
7 | export ARCH=x86_64
8 | export CLANG_TRIPLE=x86_64-linux-gnu-
9 | export CROSS_COMPILE=x86_64-linux-gnu-
10 | export LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=${ROOT_DIR}/x86_64-linux-android-4.9/bin
11 | DEVEXPS="CC=clang-11 LD=ld.lld-11 NM=llvm-nm-11 OBJCOPY=llvm-objcopy-11 DEPMOD=depmod DTC=dtc BRANCH=android12-5.10 LLVM=1 EXTRA_CMDS='' STOP_SHIP_TRACEPRINTK=1 DO_NOT_STRIP_MODULES=1 IN_KERNEL_MODULES=1 KMI_GENERATION=9 HERMETIC_TOOLCHAIN=${HERMETIC_TOOLCHAIN:-1} BUILD_INITRAMFS=1 LZ4_RAMDISK=1 LLVM_IAS=1 BUILD_GOLDFISH_DRIVERS=m BUILD_VIRTIO_WIFI=m BUILD_RTL8821CU=m"
12 | export KBUILD_BUILD_USER=build-user
13 | export KBUILD_BUILD_HOST=build-host
14 | export PATH=$LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN:$PATH
15 | (cd $KERNEL_DIR && make $DEVEXPS mrproper)
16 | (cd $KERNEL_DIR && KCONFIG_CONFIG=$KERNEL_DIR/.config $KERNEL_DIR/scripts/kconfig/merge_config.sh -m -r $KERNEL_DIR/arch/x86/configs/gki_defconfig ${ROOT_DIR}/common-modules/virtual-device/virtual_device.fragment)
17 | (cd $KERNEL_DIR && ${KERNEL_DIR}/scripts/config --file .config -d LTO -d LTO_CLANG -d LTO_CLANG_FULL -d CFI -d CFI_PERMISSIVE -d CFI_CLANG)
18 | (cd $KERNEL_DIR && make $DEVEXPS olddefconfig)
19 | (cd $KERNEL_DIR && make $DEVEXPS -j32)
20 | (cd $KERNEL_DIR && rm -rf staging && mkdir -p staging)
21 | (cd $KERNEL_DIR && make $DEVEXPS "INSTALL_MOD_STRIP=1" INSTALL_MOD_PATH=$KERNEL_DIR/staging modules_install)
22 | (cd $KERNEL_DIR && make -C $ROOT_DIR/common-modules/virtual-device M=../common-modules/virtual-device KERNEL_SRC=$KERNEL_DIR $DEVEXPS -j32 clean)
23 | (cd $KERNEL_DIR && make -C $ROOT_DIR/common-modules/virtual-device M=../common-modules/virtual-device KERNEL_SRC=$KERNEL_DIR $DEVEXPS -j32)
24 | (cd $KERNEL_DIR && make -C $ROOT_DIR/common-modules/virtual-device M=../common-modules/virtual-device KERNEL_SRC=$KERNEL_DIR $DEVEXPS -j32 "INSTALL_MOD_STRIP=1" INSTALL_MOD_PATH=$KERNEL_DIR/staging modules_install)
25 |
--------------------------------------------------------------------------------
/examples/clean-avdkernel.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # You would need to install clang-11 based toolchain (including ld.lld-11) to make this example working (or modify this example accordingly)
4 |
5 | export ROOT_DIR=$(pwd)
6 | export KERNEL_DIR=$ROOT_DIR/kernel
7 | export ARCH=x86_64
8 | export CLANG_TRIPLE=x86_64-linux-gnu-
9 | export CROSS_COMPILE=x86_64-linux-gnu-
10 | export LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=${ROOT_DIR}/x86_64-linux-android-4.9/bin
11 | DEVEXPS="CC=clang-11 LD=ld.lld-11 NM=llvm-nm-11 OBJCOPY=llvm-objcopy-11 DEPMOD=depmod DTC=dtc BRANCH=android12-5.10 LLVM=1 EXTRA_CMDS='' STOP_SHIP_TRACEPRINTK=1 DO_NOT_STRIP_MODULES=1 IN_KERNEL_MODULES=1 KMI_GENERATION=9 HERMETIC_TOOLCHAIN=${HERMETIC_TOOLCHAIN:-1} BUILD_INITRAMFS=1 LZ4_RAMDISK=1 LLVM_IAS=1 BUILD_GOLDFISH_DRIVERS=m BUILD_VIRTIO_WIFI=m BUILD_RTL8821CU=m"
12 | (cd $KERNEL_DIR && make $DEVEXPS mrproper)
13 |
--------------------------------------------------------------------------------
/examples/clone-avdkernel.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Download Linux kernel for the emulator so we could spin some examples
4 |
5 | mkdir -p avdkernel
6 | (cd avdkernel && git clone https://android.googlesource.com/kernel/build build)
7 | (cd avdkernel && git clone https://android.googlesource.com/platform/prebuilts/build-tools prebuilts/build-tools)
8 | (cd avdkernel && git clone -b android-11.0.0_r28 --single-branch https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9)
9 | (cd avdkernel && git clone https://android.googlesource.com/kernel/prebuilts/build-tools prebuilts/kernel-build-tools)
10 | (cd avdkernel && git clone https://android.googlesource.com/kernel/common-modules/virtual-device common-modules/virtual-device)
11 | (cd avdkernel/common-modules/virtual-device && git checkout 272a06c7d90c63f756ee998957609c25ebc6a6cf)
12 | (cd avdkernel && git clone https://android.googlesource.com/kernel/common kernel)
13 | (cd avdkernel/kernel && git checkout 53a812c6bbf3d88187f5f31a09b5499afc2930fb)
14 |
--------------------------------------------------------------------------------
/examples/etrace_show_info:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 | import libetrace
5 |
6 | nfsdb = libetrace.nfsdb()
7 | nfsdb.load(sys.argv[1],quiet=True)
8 |
9 | print ("Source root of the build: %s"%(nfsdb.source_root))
10 | print ("Database version: %s"%(nfsdb.dbversion))
11 |
12 | # List all linked modules
13 | L = [x for x in nfsdb if x.is_linking()]
14 | print ("# Linked modules")
15 | for x in L:
16 | print (" %s"%(x.linked_path))
17 | print()
18 |
19 | # List compiled files
20 | C = [x for x in nfsdb if x.has_compilations()]
21 | print ("# Compiled files")
22 | for x in C:
23 | for u in x.compilation_info.file_paths:
24 | print (" %s"%(u))
25 | print()
26 |
27 | # List all compilation commands
28 | print ("# Compilation commands")
29 | for x in C:
30 | print ("$ %s\n"%(" ".join(x.argv)))
31 |
--------------------------------------------------------------------------------
/examples/extract-avdkernel-info-for-ftdb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 | import libetrace
5 | import json
6 | import re
7 |
8 | nfsdb = libetrace.nfsdb()
9 | nfsdb.load(sys.argv[1],quiet=True)
10 |
11 | # Getting linked vmlinux path and list of loadable kernel modules
12 | L = [e.linked_path for e in nfsdb if e.is_linking() and (e.linked_path.endswith("vmlinux") or e.linked_path.endswith(".ko"))]
13 |
14 | # Getting file dependencies for vmlinux kernel module and all loadable modules
15 | mdeps = {}
16 | for f in L:
17 | excl_patterns = ["/dev/*"]
18 | if f.endswith(".ko"):
19 | excl_patterns.append("*.mod.c")
20 | mdeps[f]=set(nfsdb.fdeps(f,exclude_patterns=excl_patterns)[1])
21 | deps = set()
22 | for x in mdeps.values():
23 | deps|=x
24 | print ("Total dependencies: %d"%(len(deps)))
25 |
26 | cmap = {}
27 | h = re.compile("^/dev/.*")
28 | for e in nfsdb:
29 | if e.has_compilations():
30 | for cf in e.compilation_info.file_paths:
31 | if not h.match(cf):
32 | if cf not in cmap:
33 | cmap[cf] = e
34 |
35 | comps = set()
36 | for f in deps:
37 | if f in cmap:
38 | comps.add((cmap[f].eid.pid,cmap[f].eid.index))
39 | print ("Number of compilations: %d"%(len(comps)))
40 |
41 | # Generate compilation database
42 | def json_command(cmd):
43 | return json.dumps(" ".join([x.rstrip().replace("\\","\\\\").replace("\"","\\\"").replace(" ","\\ ") for x in cmd]))
44 |
45 | json_vals = list()
46 | for C in comps:
47 | eL = nfsdb[C]
48 | for e in eL:
49 | json_vals.append( "{\"directory\":%s,\"command\":%s,\"file\":%s}"%(json.dumps(e.cwd),json_command(e.argv),json.dumps(e.compilation_info.file_paths[0])) )
50 | with open("compile_commands.json","w") as f:
51 | f.write(json.dumps(json.loads("[%s]"%",".join(json_vals)), indent=4, sort_keys=False))
52 | print ("created compilation database file (compile_commands.json)")
53 |
54 | # Generate compilation dependency map
55 | cdm = {}
56 | for m,deplist in mdeps.items():
57 | cdm[m] = []
58 | for f in deplist:
59 | if f in cmap:
60 | cdm[m].append(f)
61 | with open("cdm.json","w") as f:
62 | f.write(json.dumps(cdm, indent=4, sort_keys=False))
63 | print ("created compilation dependency map file (cdm.json)")
64 |
65 | # Generate reverse dependency map file
66 | rdm = {}
67 | for m,deplist in mdeps.items():
68 | for f in deplist:
69 | if f in rdm:
70 | rdm[f].append(m)
71 | else:
72 | rdm[f] = [m]
73 | with open("rdm.json","w") as f:
74 | f.write(json.dumps(rdm, indent=4, sort_keys=False))
75 | print ("created reverse dependency map file (rdm.json)")
76 |
--------------------------------------------------------------------------------
/examples/extract-cas-info-for-ftdb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 | import libetrace
5 | import json
6 |
7 | nfsdb = libetrace.nfsdb()
8 | nfsdb.load(sys.argv[1],quiet=True)
9 |
10 | # Getting all compilations for C files
11 | comps = [e for e in nfsdb if e.has_compilations() and e.compilation_info.type==1]
12 |
13 | def json_command(cmd):
14 | return json.dumps(" ".join([x.rstrip().replace("\\","\\\\").replace("\"","\\\"").replace(" ","\\ ") for x in cmd]))
15 |
16 | json_vals = list()
17 | cfs = set()
18 | for e in comps:
19 | if e.compilation_info.files[0].path not in cfs:
20 | json_vals.append( "{\"directory\":%s,\"command\":%s,\"file\":%s}"%(json.dumps(e.cwd),json_command(e.argv),json.dumps(e.compilation_info.files[0].path)) )
21 | cfs.add(e.compilation_info.files[0].path)
22 | with open("compile_commands.json","w") as f:
23 | f.write(json.dumps(json.loads("[%s]"%",".join(json_vals)), indent=4, sort_keys=False))
24 | print ("created compilation database file (compile_commands.json)")
--------------------------------------------------------------------------------
/examples/ftdb_show_info:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 | import libftdb
5 |
6 | ftdb = libftdb.ftdb()
7 | ftdb.load(sys.argv[1],quiet=True)
8 |
9 | print ("version: %s"%(ftdb.version))
10 | print ("module: %s"%(ftdb.module))
11 | print ("directory: %s"%(ftdb.directory))
12 | print ("release: %s"%(ftdb.release))
13 |
14 | print ("Number of sources: %d"%(len(ftdb.sources)))
15 | for i,sT in enumerate(ftdb.sources):
16 | if i>=10 and i=10 and i %s"%(f.name,f.declbody))
30 | print()
31 |
32 | print ("Number of globals: %d"%(len(ftdb.globals)))
33 | for i,g in enumerate(ftdb.globals):
34 | if i>=10 and i %s"%(g.name,g.defstring))
39 | print()
40 |
41 | print ("Number of types: %d"%(len(ftdb.types)))
42 | print ("Number of plain struct types: %d"%(len([x for x in ftdb.types if x.classname=="record" and x.str!=""])))
43 | for i,T in enumerate([x for x in ftdb.types if x.classname=="record" and x.str!=""]):
44 | if i>=10 and i/examples/generate-pdf-files-for-ot / [ ] [add_project_source:]
13 |
14 | # Getting file dependencies for all linked modules in the project
15 | dep_pids = set()
16 | dep_paths = set()
17 | linked_modules = [e.linked_file for e in nfsdb if e.is_linking()]
18 | for lm in linked_modules:
19 | r = nfsdb.fdeps(lm.path)
20 | dep_pids |= set(r[0])
21 | dep_paths |= set(r[1])
22 | print ("Total dependencies: %d"%(len(dep_paths)))
23 | print ("Total compiled dependencies: %d"%(len([x for x in r[2] if x.is_compiled()])))
24 |
25 | apgn = APGN(nfsdb)
26 | source_root = sys.argv[1].rstrip("/")
27 | outdir = os.path.join(source_root,".eclipse")
28 | project_name = source_root.split(os.sep)[-1]
29 | remap_source_root = None
30 | if len(sys.argv)>2:
31 | remap_source_root = [(source_root,sys.argv[2])]
32 | add_project_source = False
33 | if len(sys.argv)>3:
34 | add_project_source = int(sys.argv)!=0
35 | apgn.generate_project_description_files(list(dep_paths),project_name,list(dep_pids),source_root,outdir,add_project_source=add_project_source,remap_source_root=remap_source_root)
36 |
--------------------------------------------------------------------------------
/examples/generate-pdf-files-for-kernel:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 | import libetrace
5 | from bas.ide import *
6 |
7 | nfsdb = libetrace.nfsdb()
8 | nfsdb.load(sys.argv[1],quiet=True)
9 | nfsdb.load_deps(sys.argv[1][:-3]+"deps.img",quiet=True)
10 |
11 | # Run it as:
12 | # python3 /examples/generate-pdf-files-for-kernel .nfsdb.json.img [ ] [add_project_source:]
13 |
14 | # Getting linked vmlinux path and list of loadable kernel modules
15 | L = [e.linked_file for e in nfsdb if e.is_linking() and (e.linked_file.path.endswith("vmlinux") or e.linked_file.path.endswith(".ko"))]
16 |
17 | # Getting file dependencies for vmlinux kernel module and all loadable modules
18 | deplst = set()
19 | for f in L:
20 | excl_patterns = ["/dev/*"]
21 | if f.path.endswith(".ko"):
22 | excl_patterns.append("*.mod.c")
23 | r = nfsdb.mdeps(f.path)
24 | deplst|=set(r)
25 | dep_paths = list(set([x.path for x in deplst]))
26 | dep_pids = list(set([x.parent.eid.pid for x in deplst]))
27 | print ("Total dependencies: %d"%(len(dep_paths)))
28 | apgn = APGN(nfsdb)
29 | source_root = sys.argv[2]
30 | outdir = sys.argv[3]
31 | remap_source_root = None
32 | if len(sys.argv)>5:
33 | remap_source_root = [(source_root,sys.argv[5])]
34 | add_project_source = False
35 | if len(sys.argv)>6:
36 | add_project_source = int(sys.argv)!=0
37 | apgn.generate_project_description_files(dep_paths,sys.argv[4],dep_pids,source_root,outdir,add_project_source=add_project_source,remap_source_root=remap_source_root)
38 |
--------------------------------------------------------------------------------
/examples/generate-pdf-files-for-ot:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 | import libetrace
5 | import os
6 | from bas.ide import *
7 |
8 | nfsdb = libetrace.nfsdb()
9 | nfsdb.load("%s/.nfsdb.img"%(sys.argv[1]),quiet=True)
10 |
11 | # Run it as:
12 | # python3 /examples/generate-pdf-files-for-ot / [ ] [add_project_source:]
13 |
14 | # Getting file dependencies for the 'native' OT executable
15 | native_path = [e.linked_file for e in nfsdb if e.is_linking() and e.linked_file.path.endswith("native")][0].path
16 | r = nfsdb.fdeps(native_path)
17 | dep_pids = r[0]
18 | dep_paths = r[1]
19 | print ("Total dependencies: %d"%(len(dep_paths)))
20 | print ("Total compiled dependencies: %d"%(len([x for x in r[2] if x.is_compiled()])))
21 |
22 | apgn = APGN(nfsdb)
23 | source_root = sys.argv[1].strip("/")
24 | outdir = os.path.join(source_root,".eclipse")
25 | project_name = source_root.split(os.sep)[-1]
26 | remap_source_root = None
27 | if len(sys.argv)>2:
28 | remap_source_root = [(source_root,sys.argv[2])]
29 | add_project_source = False
30 | if len(sys.argv)>3:
31 | add_project_source = int(sys.argv)!=0
32 | apgn.generate_project_description_files(dep_paths,project_name,dep_pids,source_root,outdir,add_project_source=add_project_source,remap_source_root=remap_source_root)
33 |
--------------------------------------------------------------------------------
/libft_db.py:
--------------------------------------------------------------------------------
1 | import libftdb
2 | from libcas import CASConfig
3 | from typing import List, Optional
4 | from functools import lru_cache
5 |
6 | class ftdbSourceEntry:
7 |
8 | def __init__(self, fid: int, path: str) -> None:
9 | self.fid = fid
10 | self.path = path
11 |
12 |
13 | class ftdbModuleEntry:
14 |
15 | def __init__(self, mid: int, path: str) -> None:
16 | self.mid = mid
17 | self.path = path
18 |
19 |
20 | class FTDatabase:
21 | """
22 | Ftdb database wrapper
23 | """
24 |
25 | db: libftdb.ftdb
26 | db_loaded: bool
27 | config: CASConfig
28 |
29 | def __init__(self) -> None:
30 | self.db = libftdb.ftdb()
31 | self.db_loaded = False
32 | self.db_path = None
33 |
34 | def load_db(self, db_path: str, quiet:bool=True, debug:bool=False) -> bool:
35 | self.db_loaded = self.db.load(db_path, quiet=quiet, debug=debug)
36 | self.db_path = db_path
37 | return self.db_loaded
38 |
39 | def unload_db(self) -> bool:
40 | del self.db
41 | self.db = libftdb.ftdb()
42 | return True
43 |
44 | def get_version(self) -> str:
45 | return self.db.version
46 |
47 | def get_module_name(self) -> str:
48 | return self.db.module
49 |
50 | def get_dir(self) -> str:
51 | return self.db.directory
52 |
53 | def get_release(self) -> str:
54 | return self.db.release
55 |
56 | def get_sources(self, fids=None) -> List[ftdbSourceEntry]:
57 | if fids is None:
58 | return [ftdbSourceEntry(s[0], s[1]) for s in list(self.db.sources)]
59 | return [ftdbSourceEntry(fid, self.db.sources[fid]) for fid in set(fids) if fid < len(self.db.sources)]
60 |
61 | def get_modules(self, mids=None) -> List[ftdbModuleEntry]:
62 | if mids is None:
63 | return [ftdbModuleEntry(md[0], md[1]) for md in list(self.db.modules)]
64 | return [ftdbModuleEntry(mid, self.db.modules[mid]) for mid in set(mids) if mid < len(self.db.modules)]
65 |
66 | def get_funcs(self, fids: Optional[List[int]]=None) -> List[libftdb.ftdbFuncEntry]:
67 | if fids is None:
68 | return self.db.funcs
69 | return [func for func in self.db.funcs if set(func.fids).intersection(fids)]
70 |
71 | def get_funcdecls(self, fids:Optional[List[int]]=None) -> List[libftdb.ftdbFuncdeclEntry]:
72 | if fids is None:
73 | return self.db.funcdecls
74 | return [fd for fd in self.db.funcdecls if fd.fid in fids]
75 |
76 | def get_globs(self, fids: Optional[List[int]]=None) -> List[libftdb.ftdbGlobalEntry]:
77 | if fids is None:
78 | return self.db.globals
79 | return [glob for glob in self.db.globals if glob.fid in fids]
80 |
81 | def get_types(self) -> libftdb.ftdbTypes:
82 | return self.db.types
83 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pathlib
3 | from setuptools import Extension, setup
4 | from setuptools.command.build_ext import build_ext as build_ext_orig
5 |
6 |
7 | class CMakeExtension(Extension):
8 | def __init__(self, name, makefile_target):
9 | self.makefile_target = makefile_target
10 | super().__init__(name, sources=[])
11 |
12 |
13 | class CMakeBuild(build_ext_orig):
14 | def build_extension(self, ext: CMakeExtension):
15 | cwd = pathlib.Path().absolute()
16 |
17 | build_temp = pathlib.Path.joinpath(pathlib.Path().absolute(), "build_release")
18 | build_temp.mkdir(parents=True, exist_ok=True)
19 | ext_fullpath = pathlib.Path.cwd() / self.get_ext_fullpath(ext.name)
20 | extdir = ext_fullpath.parent.resolve()
21 | os.chdir(str(build_temp))
22 | if not pathlib.Path.exists(pathlib.Path('Makefile')):
23 | self.spawn(['cmake', f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}", '-DCMAKE_BUILD_TYPE=Release', '-DCMAKE_C_COMPILER=clang', '-DCMAKE_CXX_COMPILER=clang++', '..'])
24 | self.spawn(['make', '-j16', ext.makefile_target])
25 | os.chdir(str(cwd))
26 |
27 |
28 | setup(
29 | name='libcas',
30 | version='1.0',
31 | packages=['client','client.output_renderers','bas', ''],
32 | url='https://github.sec.samsung.net/CO7-SRPOL-Mobile-Security/CAS-OSS',
33 | author="MobileSecurity",
34 | author_email='mbsec@samsung.com',
35 | scripts=['cas'],
36 | ext_modules=[
37 | CMakeExtension(name="libetrace", makefile_target="etrace"),
38 | CMakeExtension(name="libftdb", makefile_target="ftdb")],
39 | cmdclass={
40 | 'build_ext': CMakeBuild,
41 | }
42 | )
43 |
44 | # run it with
45 | # rm -r build/ build_release/ dist/ libcas.egg-info/ && python3 -m build -w --no-isolation
--------------------------------------------------------------------------------
/setup_etrace.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | print_usage () {
4 | echo "Usage: $0 (-i ROOT_PID [...]|-r|-f)"
5 | }
6 |
7 | if [ "$#" -lt 1 ]; then
8 | print_usage
9 | exit 1
10 | fi
11 |
12 | if [ "$1" = "-f" ]; then
13 | # set up ftrace
14 |
15 | # After system restart the second chmod may actually not work,
16 | # even if run as root. Experiments show that it is probably
17 | # caused by lazy creation of tracefs, because poking this
18 | # filesystem in some other way (i.e. ls) magically causes
19 | # chmod to work again. So, do a dummy ls before second chmod.
20 | chmod 755 /sys/kernel/debug
21 | if [ "$?" -ne 0 ]; then exit "$?"; fi
22 | ls /sys/kernel/debug/tracing 1>/dev/null 2>/dev/null
23 | chmod 755 /sys/kernel/debug/tracing
24 | chmod 755 /sys/kernel/debug/tracing/trace_pipe
25 | chmod 755 -R /sys/kernel/debug/tracing/per_cpu/
26 | if [ "$?" -ne 0 ]; then exit "$?"; fi
27 |
28 | # set buffers size
29 | if [ ! -z "${TRACING_BUFF_SIZE_KB}" ]; then
30 | echo "${TRACING_BUFF_SIZE_KB}" > /sys/kernel/debug/tracing/buffer_size_kb
31 | else
32 | echo "262144" > /sys/kernel/debug/tracing/buffer_size_kb
33 | fi
34 | if [ "$?" -ne 0 ]; then
35 | exit "$?"
36 | fi
37 |
38 | # Remove log headers
39 | echo "nocontext-info" > /sys/kernel/debug/tracing/trace_options
40 |
41 | # clear buffers
42 | echo "dummy" > "/sys/kernel/debug/tracing/trace"
43 | if [ "$?" -ne 0 ]; then
44 | exit "$?"
45 | fi
46 |
47 | elif [ "$1" = "-i" ]; then
48 | if [ "$#" -lt 2 ]; then
49 | print_usage
50 | exit 1
51 | fi
52 |
53 | # install module
54 | SUPPORT_NS_PID=""
55 | uname -r | grep WSL > /dev/null && SUPPORT_NS_PID="support_ns_pid=1"
56 | if [ ! -z "${SUPPORT_NS_PID}" ]; then
57 | echo SUPPORT_NS_PID=$SUPPORT_NS_PID
58 | fi
59 | /sbin/modprobe bas_tracer root_pid="$2" "$SUPPORT_NS_PID" "${@:3}"
60 | exit "$?"
61 |
62 | elif [ "$1" = "-r" ]; then
63 | /sbin/rmmod bas_tracer
64 | echo "1410" > /sys/kernel/debug/tracing/buffer_size_kb
65 | exit "$?"
66 | else
67 | print_usage
68 | fi
69 |
70 |
--------------------------------------------------------------------------------
/tests/ftdb_sha256_test.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "openssl/sha.h"
4 | #include "ftdb.h"
5 |
6 | int main(int argc, char** argv) {
7 |
8 | if (argc<=1) {
9 | fprintf(stderr,"Usage: ./ftdb_sha256_test \n");
10 | return EXIT_FAILURE;
11 | }
12 |
13 | CFtdb ftdb_c = libftdb_c_ftdb_load(argv[1], 0, 0);
14 | if (!ftdb_c) {
15 | return EXIT_FAILURE;
16 | }
17 |
18 | struct ftdb* ftdb = libftdb_c_ftdb_object(ftdb_c);
19 |
20 | SHA256_CTX ctx;
21 | SHA256_Init(&ctx);
22 | unsigned char digest[SHA256_DIGEST_LENGTH];
23 |
24 | for (unsigned long i=0; ifuncs_count; ++i) {
25 | struct ftdb_func_entry* func_entry = &ftdb->funcs[i];
26 | SHA256_Update(&ctx,(const unsigned char*)func_entry->body,strlen(func_entry->body));
27 | SHA256_Update(&ctx,(const unsigned char*)func_entry->unpreprocessed_body,strlen(func_entry->unpreprocessed_body));
28 | for (unsigned long j=0; jderefs_count; ++j) {
29 | struct deref_info* deref_info = &func_entry->derefs[j];
30 | uint64_t deref_kind = deref_info->kind;
31 | SHA256_Update(&ctx,(const unsigned char*)&deref_kind,sizeof(uint64_t) );
32 | }
33 | for (unsigned long j=0; jtypes_count; ++j) {
34 | unsigned long type_id = func_entry->types[j];
35 | struct ftdb_type_entry* type_entry = libftdb_c_get_type_entry_by_id(ftdb_c, type_id);
36 | if (type_entry->def) {
37 | SHA256_Update(&ctx,(const unsigned char*)type_entry->def,strlen(type_entry->def));
38 | }
39 | }
40 | }
41 | for (unsigned long i=0; iglobals_count; ++i) {
42 | struct ftdb_global_entry* global_entry = &ftdb->globals[i];
43 | unsigned long type_id = global_entry->type;
44 | struct ftdb_type_entry* type_entry = libftdb_c_get_type_entry_by_id(ftdb_c, type_id);
45 | if (type_entry->def) {
46 | SHA256_Update(&ctx,(const unsigned char*)type_entry->def,strlen(type_entry->def) );
47 | }
48 | }
49 |
50 | SHA256_Final(digest,&ctx);
51 |
52 | for (int i=0; i<32; ++i) {
53 | printf("%02x",digest[i]);
54 | }
55 | printf("\n");
56 |
57 | libftdb_c_ftdb_unload(ftdb_c);
58 | return EXIT_SUCCESS;
59 | }
60 |
--------------------------------------------------------------------------------
/tests/ftdb_sha256_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import libftdb
4 | import hashlib
5 | import sys
6 |
7 | ftdb = libftdb.ftdb()
8 | ftdb.load(sys.argv[1])
9 |
10 | m = hashlib.sha256()
11 |
12 | for f in ftdb.funcs:
13 | m.update(f.body.encode('ascii'))
14 | m.update(f.unpreprocessed_body.encode('ascii'))
15 | for D in f.derefs:
16 | m.update(D.kind.to_bytes(8,byteorder='little'))
17 | for T in f.types:
18 | if "def" in ftdb.types[T]:
19 | m.update(ftdb.types[T].defstring.encode('ascii'))
20 |
21 | for g in ftdb.globals:
22 | if "def" in ftdb.types[g.type]:
23 | m.update(ftdb.types[g.type].defstring.encode('ascii'))
24 |
25 | print (m.hexdigest())
26 |
--------------------------------------------------------------------------------
/tools/bash_completion/cas_completion.sh:
--------------------------------------------------------------------------------
1 | #/usr/bin/env bash
2 | _cas_completions() {
3 | COMPREPLY=($(compgen -W "`cas bash_complete ${COMP_WORDS[@]}`" -- "$2" ))
4 | }
5 |
6 | complete -F _cas_completions cas
--------------------------------------------------------------------------------
/tools/virtual_environment/img_build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | IMG_URL=https://cloud-images.ubuntu.com/minimal/releases/focal/release/ubuntu-20.04-minimal-cloudimg-amd64.img
3 | IMG_RESIZE_SIZE=20G
4 | MEM=$(free --mega | grep "Mem:" | awk '{printf "%.0f",($2 * 0.8)}')
5 | PROC=$(nproc | awk '{printf "%.0f",($1 * 0.8)}')
6 |
7 | SOCKETS=$(lscpu -J | jq -r '.lscpu[]| select(.field=="Socket(s):").data')
8 | CORES=$(lscpu -J | jq -r '.lscpu[]| select(.field=="Core(s) per socket:").data')
9 | TPERCORE=$(lscpu -J | jq -r '.lscpu[]| select(.field=="Thread(s) per core:").data')
10 |
11 | IMG=system_base.img
12 | if [ ! -f "${IMG}" ]; then
13 | echo "Downloading image from ${IMG_URL} to ${IMG}"
14 | curl -s -o ${IMG} "${IMG_URL}" || { echo "Download fail"; rm ${IMG}; exit 2; }
15 | fi
16 |
17 | BOOT_IMG=$(cat /proc/cmdline | awk '{split($1,x,"="); print x[2]}')
18 | if [ ! -r "/boot/${BOOT_IMG#/}" ]; then
19 | if [ ! -f "${BOOT_IMG#/}" ] ; then
20 | echo "**************************************************************"
21 | echo "Can't read booted kernel file. Probably you are running Ubuntu (where access to kernel image is blocked for user)."
22 | echo "Copying /boot/${BOOT_IMG#/} to current dir."
23 | echo "**************************************************************"
24 | sudo cp /boot/${BOOT_IMG#/} .
25 | sudo chown $USER:$USER ${BOOT_IMG#/}
26 | fi
27 | export SUPERMIN_KERNEL=$(pwd)/${BOOT_IMG#/}
28 | fi
29 |
30 | IMG_RESIZED=system_resized.img
31 | if [ ! -f "$IMG_RESIZED" ]; then
32 | echo "Resizing image"
33 | qemu-img create -f qcow2 ${IMG_RESIZED} ${IMG_RESIZE_SIZE} || { echo "Create resized fail"; exit 2; }
34 | virt-resize --format=qcow2 --expand /dev/sda1 ${IMG} ${IMG_RESIZED} | tee /tmp/resize_info || { echo "Resize fail"; rm ${IMG_RESIZED}; exit 2; }
35 | EXPANDED_PARTITION=$(grep "Expanding" /tmp/resize_info | sed -r 's/.*now (\/dev\/.+)\).*/\1/g')
36 | rm /tmp/resize_info
37 | echo "Reinstalling grub on ${EXPANDED_PARTITION}"
38 | virt-customize -a ${IMG_RESIZED} -smp ${PROC} -m ${MEM} \
39 | --run-command "mkdir -p /mnt && mount ${EXPANDED_PARTITION} /mnt && mount --bind /dev /mnt/dev && mount --bind /proc /mnt/proc && mount --bind /sys /mnt/sys && chroot /mnt && grub-install /dev/sda" || { echo "Grub install fail"; rm ${IMG_RESIZED}; exit 2; }
40 | fi
41 |
42 | IMG_WORK=cas_tracer_env.img
43 | if [ ! -f "${IMG_WORK}" ]; then
44 | cp "${IMG_RESIZED}" "${IMG_WORK}"
45 |
46 | echo "Customizing image"
47 | echo " -installing packages"
48 | virt-customize -a ${IMG_WORK} -smp ${PROC} -m ${MEM} \
49 | --root-password password:pass \
50 | --install "build-essential,linux-headers-generic,git,cmake,llvm,clang,clang-10,libclang-dev,python3-dev,gcc-9-plugin-dev,rsync,clang-11,flex,bison,lld-11,libssl-dev,file,python2,python2.7-numpy,python-futures" || { echo "Customizing fail"; rm ${IMG_WORK}; exit 2; }
51 |
52 | echo " -cloning and building CAS packages"
53 | virt-customize -a ${IMG_WORK} -smp ${PROC} -m ${MEM} \
54 | --mkdir /opt/ \
55 | --run-command 'rm -rf /opt/cas/ && git clone https://github.com/Samsung/CAS.git /opt/cas/' \
56 | --run-command 'cd /opt/cas/tracer/ && make -C /lib/modules/$(ls /lib/modules/ | grep kvm)/build M=$PWD && make -C /lib/modules/$(ls /lib/modules/ | grep kvm)/build M=$PWD modules_install' \
57 | --run-command 'cd /opt/cas/bas/ && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .. && make && make install' \
58 | --run-command 'cd /opt/cas/ && ./etrace_install.sh' \
59 | --run-command 'echo "\nexport PATH=\"/opt/cas/:$PATH"\" >> /root/.bashrc' \
60 | --firstboot-command "depmod -a" || { echo "Customizing fail"; rm ${IMG_WORK}; exit 2; }
61 |
62 | echo " -enable network and ssh"
63 | virt-customize -a ${IMG_WORK} -smp ${PROC} -m ${MEM} \
64 | --run-command "sed -i 's/GRUB_CMDLINE_LINUX=/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g' /etc/default/grub" \
65 | --run-command "update-grub" \
66 | --run-command "echo '
67 | network:
68 | version: 2
69 | renderer: networkd
70 | ethernets:
71 | eth0:
72 | dhcp4: true
73 | optional: true
74 | ' > /etc/netplan/01-netcfg.yaml" \
75 | --firstboot-command "netplan generate && netplan apply" \
76 | --firstboot-command "dpkg-reconfigure openssh-server" || { echo "Customizing fail"; rm ${IMG_WORK} exit 2; }
77 |
78 | echo "Image ${IMG_WORK} customized."
79 | else
80 | echo "Image ${IMG_WORK} already built."
81 | fi
82 |
83 | echo "\nExample next steps"
84 |
85 | echo -e "\n* Create source image"
86 | echo "virt-make-fs --format=qcow2 --size=+10G /some/source/dir/ src.img"
87 |
88 | echo -e "\n* Create a work layer - it will make src.img immutable."
89 | echo "qemu-img create -f qcow2 -b src.img -F qcow2 work.qcow2"
90 |
91 | echo -e "\n* Run Qemu"
92 | echo "qemu-system-x86_64 --enable-kvm -nographic -cpu host -m ${MEM} -smp cores=${CORES},threads=${TPERCORE},sockets=${SOCKETS} -drive file=cas_tracer_env.img -drive file=work.qcow2 -device virtio-net,netdev=vmnic -netdev user,id=vmnic"
93 |
--------------------------------------------------------------------------------
/tracer/LICENSE:
--------------------------------------------------------------------------------
1 | Build Awareness Service (BAS) tracer utility, part of the Code Aware Services (CAS) suite
2 | Copyright (C) 2022 Samsung Electronics Co., Ltd.
3 |
4 | This program is free software. Unless otherwise stated below,
5 | the files in this project may be distributed under the terms
6 | of the GNU General Public License version 2.
7 |
8 | This program is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | GNU General Public License for more details.
12 |
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 |
--------------------------------------------------------------------------------
/tracer/Makefile:
--------------------------------------------------------------------------------
1 | KERNEL_PATH ?= /lib/modules/$(shell uname -r)/build
2 |
3 | obj-m += bas_tracer.o
4 |
5 | TRACER_DIR ?= $(PWD)
6 | GIT_COMMIT ?= $(shell git -C $(TRACER_DIR) describe --always --dirty)
7 | COMPILATION_TIME ?= $(shell date "+%F %T")
8 | ccflags-y += -DGIT_COMMIT="\"$(GIT_COMMIT)\"" -DCOMPILATION_TIME="\"$(COMPILATION_TIME)\""
9 |
10 | all:
11 | make -C $(KERNEL_PATH) M=$(PWD) modules
12 |
13 | clean:
14 | make -C $(KERNEL_PATH) M=$(PWD) clean
15 |
16 | modules_install:
17 | make -C $(KERNEL_PATH) M=$(shell pwd) modules_install
18 | depmod
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tracer/README.md:
--------------------------------------------------------------------------------
1 | ## Syscalls tracing kernel module
2 | A linux kernel module for tracing selected syscalls. Inspired by https://github.com/ilammy/ftrace-hook.
3 |
4 | ### Build & Installation
5 | 1. Get packages needed for module build.
6 | ```bash
7 | $ sudo apt install build-essential linux-headers-$(uname -r)
8 | ```
9 | 2. Build and install the module.
10 | ```bash
11 | $ make
12 | $ sudo make modules_install
13 | ```
14 | Some kernel configurations may require modules to be signed. To do so, follow the instructions in [kernel module signing docs](https://www.kernel.org/doc/html/latest/admin-guide/module-signing.html).
15 |
16 | ### WSL build
17 | 1. Check kernel version:
18 | ```bash
19 | $ uname -r
20 | 5.15.90.1-microsoft-standard-WSL2
21 | ```
22 | 2. Find and download proper kernel sources version from: [WSL2-Linux-Kernel](https://github.com/microsoft/WSL2-Linux-Kernel/tags)
23 | ```bash
24 | $ wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-5.15.90.1.tar.gz
25 | $ tar -xzf linux-msft-wsl-5.15.90.1
26 | $ cd WSL2-Linux-Kernel-linux-msft-wsl-5.15.90.1
27 | ```
28 | 3. Create directories for kernel modules
29 | ```bash
30 | $ sudo mkdir -p /lib/modules/`uname -r`
31 | $ ln -s `pwd` /lib/modules/`uname -r`/build
32 | ```
33 | 4. Compile kernel and prepare kernel build enviroment for compiling modules
34 | ```bash
35 | $ zcat /proc/config.gz > Microsoft/current-config # This command gets the config of running kernel (it should be same as Microsoft/config-wsl)
36 | $ sudo apt install make gcc git bc build-essential flex bison libssl-dev libelf-dev pahole
37 | $ make KCONFIG_CONFIG=Microsoft/config-wsl -j $(nproc)
38 | $ make KCONFIG_CONFIG=Microsoft/config-wsl prepare_modules
39 | $ cp /sys/kernel/btf/vmlinux .
40 | ```
41 | 5. Proceed normal module compilation steps [Build & Installation](#build--installation)
42 | 6. Remember to mount debugfs before using etrace to be sure trace\_pipe exists
43 | ```bash
44 | $ sudo mount -t debugfs none /sys/kernel/debug
45 | ```
46 |
47 | ### Usage
48 | **Note**: commands described here are useful mostly for BAS developers. For end-user usage, see [README](../README.md) of main BAS project.
49 |
50 | This module traces the whole process tree starting from a given root pid. To start the module, use insmod or modprobe:
51 | ```bash
52 | # run from tracer directory
53 | $ sudo insmod bas_tracer.ko root_pid=
54 |
55 | # can be run from anywhere if "sudo make modules_install" was done
56 | $ sudo modprobe bas_tracer root_pid=
57 | ```
58 | specifying the process tree root pid in root_pid parameter. Currently, only pids from root namespace are supported.
59 |
60 | Successful start is indicated in dmesg:
61 | ```
62 | [ 269.189775] bas_tracer: et_init called
63 | [ 269.190147] bas_tracer: Attaching to tracepoint: sys_enter
64 | [ 269.190689] bas_tracer: Attaching to tracepoint: sys_exit
65 | [ 269.191225] bas_tracer: Attaching to tracepoint: sched_process_exit
66 | [ 269.191830] bas_tracer: Attaching to tracepoint: sched_process_fork
67 | [ 269.192440] bas_tracer: Attaching to tracepoint: sched_process_exec
68 | [ 269.193142] bas_tracer: Module loaded
69 |
70 | ```
71 |
72 | To remove the module use rmmod:
73 | ```bash
74 | $ sudo rmmod bas_tracer
75 | ```
76 |
77 | The module puts data about traced processes into trace_pipe:
78 | ```bash
79 | $ sudo cat /sys/kernel/debug/tracing/trace_pipe
80 | ```
81 | to track per-cpu buffers:
82 | ```bash
83 | $ sudo cat /sys/kernel/debug/tracing/per_cpu/cpu0/trace_pipe
84 | $ sudo cat /sys/kernel/debug/tracing/per_cpu/cpu1/trace_pipe
85 | # etc...
86 | ```
87 | Example output:
88 | ```
89 | 0: 6497,31,1586953334,420390722!New_proc|argsize=31,prognameisize=7,prognamepsize=7,cwdsize=35
90 | 0: 6497,31,1586953334,420392205!PI|/bin/sh
91 | 0: 6497,31,1586953334,420392956!PP|/bin/sh
92 | 0: 6497,31,1586953334,420393557!CW|/media/storage/tools/execve_tracing
93 | 0: 6497,31,1586953334,420396052!A[0]sh
94 | 0: 6497,31,1586953334,420397364!A[1]/usr/bin/setup_etrace.sh
95 | 0: 6497,31,1586953334,420398486!A[2]-r
96 | 0: 6497,31,1586953334,420399118!End_of_args|
97 | 0: 6496,60,1586953334,420415598!Close|fd=5
98 | 0: 6497,31,1586953334,420435295!Open|fnamesize=16,flags=524288,mode=0,fd=3
99 | 0: 6497,31,1586953334,420436137!FN|/etc/ld.so.cache
100 | 0: 6497,31,1586953334,420438701!Close|fd=3
101 | ```
102 |
103 | The description of the format used by tracer is available in [OUTPUT.md](./OUTPUT.md).
104 |
--------------------------------------------------------------------------------
/tracer/tests/execve/execveat_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This program calls execveat() syscall to check if absolute program path
3 | * resolution works as expected in "at" case (i.e. relative paths are
4 | * resolved against some other fd than AT_FDCWD). The result from running
5 | * this program under tracer should be similar to the following:
6 | *
7 | * !New_proc|argsize=16,prognameisize=50,prognamepsize=50,cwdsize=36
8 | * !PI|/full/path/to/execveat_test
9 | * !PP|/full/path/to/execveat_test
10 | * !CW|/some/full/cwd/path
11 | * !A[0]./execveat_test
12 | * !End_of_args|
13 | * ...
14 | * !New_proc|argsize=5,prognameisize=7,prognamepsize=7,cwdsize=36
15 | * !PI|/bin/ls # full path here
16 | * !PP|/bin/ls # full path here
17 | * !CW|/some/full/cwd/path
18 | * !A[0]./ls
19 | * !End_of_args|
20 | */
21 |
22 | #define _GNU_SOURCE
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | int execveat(int fd, char* fname, char** argv, char** envp, int flags) {
30 | return syscall(SYS_execveat, fd, fname, argv, envp, flags);
31 | }
32 |
33 | int main(int argc, char** argv, char** envp) {
34 |
35 | char* nargv[] = {"./ls", NULL};
36 |
37 | int binfd = open("/bin", O_DIRECTORY | O_PATH);
38 |
39 | int ret = execveat(binfd, "./ls", nargv, envp, 0);
40 | if (ret) {
41 | return 42;
42 | }
43 | return 0;
44 | }
45 |
--------------------------------------------------------------------------------
/tracer/tests/ignore_opens/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | TESTS_DIR=$(dirname "$0")
3 | for f in $TESTS_DIR/*.c; do
4 | gcc $f -o "$TESTS_DIR"/$(basename "$f" ".c")
5 | done
6 |
--------------------------------------------------------------------------------
/tracer/tests/ignore_opens/invalid_close.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char** argv) {
7 |
8 | for (int i = 0; i < 4; i++) {
9 | int fd = open("/dev/null", O_RDONLY);
10 | printf(" %d ", fd);
11 | close(fd+100);
12 | close(fd);
13 | }
14 | for (int i = 0; i < 4; i++) {
15 | int fd = open("/dev/zero", O_RDONLY);
16 | printf(" %d ", fd);
17 | close(fd+100);
18 | close(fd);
19 | }
20 | printf("\n");
21 | }
22 |
--------------------------------------------------------------------------------
/tracer/tests/ignore_opens/mixed_opens.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char** argv) {
7 |
8 | for (int i = 0; i < 4; i++) {
9 | int fd = open("/dev/null", O_RDONLY);
10 | printf(" %d ", fd);
11 | close(fd);
12 | }
13 | for (int i = 0; i < 4; i++) {
14 | int fd = open("/dev/zero", O_RDONLY);
15 | printf(" %d ", fd);
16 | close(fd);
17 | }
18 | printf("\n");
19 | }
20 |
--------------------------------------------------------------------------------
/tracer/tests/ignore_opens/mixed_opens_interleaved.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char** argv) {
7 |
8 | int fds[4];
9 | for (int i = 0; i < 4; i++) {
10 | fds[i] = open("/dev/null", O_RDONLY);
11 | printf(" %d ", fds[i]);
12 | }
13 | for (int i = 0; i < 4; i++) {
14 | int fd = open("/dev/zero", O_RDONLY);
15 | printf(" %d ", fd);
16 | close(fd);
17 | }
18 | for (int i = 0; i < 4; i++)
19 | close(fds[i]);
20 | printf("\n");
21 | }
22 |
--------------------------------------------------------------------------------
/tracer/tests/ignore_opens/open16_close_open.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char** argv) {
7 | int fds[16];
8 | for (int i = 0; i < 16; i++) {
9 | fds[i] = open("/dev/null", O_RDONLY);
10 | printf(" %d ", fds[i]);
11 | }
12 | printf("\n");
13 | close(fds[0]);
14 | open("/dev/null", O_RDONLY); // fd intentionally not closed explicitly
15 | for (int i = 1; i < 16; i++) {
16 | close(fds[i]);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tracer/tests/ignore_opens/open_close_interleaved.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char** argv) {
7 | int fds[50];
8 | for (int i = 0; i < 50; i++) {
9 | fds[i] = open("/dev/null", O_RDONLY);
10 | printf(" %d ", fds[i]);
11 | }
12 | for (int i = 0; i < 50; i++) {
13 | close(fds[i]);
14 | }
15 | printf("\n");
16 | }
17 |
--------------------------------------------------------------------------------
/tracer/tests/ignore_opens/open_close_reversed.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char** argv) {
7 | int fds[5];
8 | for (int i = 0; i < 5; i++) {
9 | fds[i] = open("/dev/null", O_RDONLY);
10 | printf(" %d ", fds[i]);
11 | }
12 | for (int i = 5; i != 0; i--) {
13 | close(fds[i-1]);
14 | }
15 | printf("\n");
16 | }
17 |
--------------------------------------------------------------------------------
/tracer/tests/ignore_opens/open_close_seq.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char** argv) {
7 |
8 | for (int i = 0; i < 50; i++) {
9 | int fd = open("/dev/null", O_RDONLY);
10 | printf(" %d ", fd);
11 | close(fd);
12 | }
13 | printf("\n");
14 | }
15 |
--------------------------------------------------------------------------------
/tracer/tests/open/multiple_opens.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | int main(int argc, char** argv) {
13 |
14 | #define CHECK(x) do {\
15 | if ((x) < 0) {\
16 | printf("%s failed: %d (%s)\n", #x, errno, strerror(errno));\
17 | }\
18 | } while (0)
19 |
20 | // regular file, absolute path
21 | CHECK(open("/bin/ls", O_RDONLY));
22 |
23 | // regular file, relative path
24 | CHECK(open("./../../../../../../../../../../../../../bin/ls", O_RDONLY));
25 |
26 | // symlink in the middle, absolute path
27 | CHECK(open("/proc/self/status", O_RDONLY));
28 |
29 | // symlink in the middle, relative path
30 | CHECK(open("../../../../../../../../../../../../../proc/self/status", O_RDONLY));
31 |
32 |
33 | // OPENAT(AT_FDCWD)
34 |
35 | // regular file, absolute path
36 | CHECK(openat(AT_FDCWD, "/bin/ls", O_RDONLY));
37 |
38 | // regular file, relative path
39 | CHECK(openat(AT_FDCWD, "./../../../../../../../../../../../../../bin/ls", O_RDONLY));
40 |
41 | // symlink in the middle, absolute path
42 | CHECK(openat(AT_FDCWD, "/proc/self/status", O_RDONLY));
43 |
44 | // symlink in the middle, relative path
45 | CHECK(openat(AT_FDCWD, "../../../../../../../../../../../../../proc/self/status", O_RDONLY));
46 |
47 | // empty name (?)
48 | // CHECK(openat(AT_FDCWD, "", O_RDONLY)); // ENOENT
49 |
50 | // null name (?)
51 | // CHECK(openat(AT_FDCWD, NULL, O_RDONLY)); // EBADADDR
52 |
53 |
54 | // OPENAT(custom_fd)
55 |
56 | int custom_fd = open("/bin", O_RDONLY | O_DIRECTORY);
57 | if (custom_fd < 0) {
58 | printf("open(custom_fd) failed, aborting: %d (%s)\n", errno, strerror(errno));
59 | return 1;
60 | }
61 |
62 | // regular file, absolute path
63 | CHECK(openat(custom_fd, "/bin/ls", O_RDONLY));
64 |
65 | // regular file, relative path
66 | CHECK(openat(custom_fd, "ls", O_RDONLY));
67 |
68 | // symlink in the middle, absolute path
69 | CHECK(openat(custom_fd, "/proc/self/status", O_RDONLY));
70 |
71 | // symlink in the middle, relative path
72 | CHECK(openat(custom_fd, "../../../../../../../../../../../../../proc/self/status", O_RDONLY));
73 |
74 |
75 | // OPEN(O_PATH)
76 |
77 | CHECK(openat(custom_fd, "../../../../../../../../../../../../../proc/self/status", O_RDONLY | O_PATH));
78 |
79 |
80 | // long path
81 | int segments = 400;
82 | if (argc == 2)
83 | segments = atoi(argv[1]);
84 |
85 | // char buf[3 * segments + sizeof("/bin/ls")] = {0};
86 |
87 | char *buf = calloc(3 * segments + sizeof("/bin/ls"), 1);
88 |
89 | for (int i = 0; i < segments; i++)
90 | strncpy(buf + i*3, "../", 3);
91 |
92 | strncpy(buf + segments*3, "/bin/ls", sizeof("/bin/ls"));
93 |
94 | CHECK(openat(AT_FDCWD, buf, O_RDONLY));
95 |
96 | return 0;
97 | }
98 |
--------------------------------------------------------------------------------
/tracer/tests/thread_name/comm.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char** argv) {
8 |
9 | char new_name[] = "new_prog_name";
10 | int ret = prctl(PR_SET_NAME, new_name);
11 | if (ret != 0) {
12 | perror("prctl() failed");
13 | return 1;
14 | }
15 |
16 | char new_pt_name[] = "new_pt_name";
17 | ret = pthread_setname_np(pthread_self(), new_pt_name);
18 | if (ret != 0) {
19 | printf("pthread_setname_np() failed, ret=%d", ret);
20 | return 1;
21 | }
22 |
23 | return 0;
24 | }
25 |
--------------------------------------------------------------------------------
/tracer/tests/thread_name/comm_pthread.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | void* thread_fn(void* arg) {
9 | char new_pt_name[] = "123456789012345";
10 |
11 | sleep(1);
12 |
13 | int ret = pthread_setname_np(pthread_self(), new_pt_name);
14 | if (ret) {
15 | printf("pthread_setname_np() from thread_fn failed, ret=%d\n", ret);
16 | }
17 | return NULL;
18 | }
19 |
20 | int main(int argc, char** argv) {
21 |
22 | pthread_t new_thread;
23 |
24 | int ret = pthread_create(&new_thread, NULL, thread_fn, NULL);
25 | if (ret) {
26 | printf("pthread_create() failed, ret=%d\n", ret);
27 | return 1;
28 | }
29 |
30 | char new_pt_name[] = "new_name";
31 | ret = pthread_setname_np(new_thread, new_pt_name);
32 | if (ret) {
33 | printf("pthread_setname_np() failed, ret=%d\n", ret);
34 | }
35 |
36 | ret = pthread_join(new_thread, NULL);
37 | if (ret) {
38 | printf("pthread_join() failed, ret=%d\n", ret);
39 | }
40 |
41 | return ret;
42 | }
43 |
--------------------------------------------------------------------------------