├── .gitignore ├── .gitmodules ├── CLIENT.md ├── CMakeLists.txt ├── CREDITS ├── LICENSE ├── README.md ├── bas ├── .bas_config ├── BS_thread_pool.hpp ├── LICENSE ├── LICENSE.txt ├── README.md ├── armcc.py ├── base64.c ├── clang.py ├── compiler.c ├── compiler.h ├── compiler_armcc.c ├── compiler_clang.c ├── compiler_gcc.c ├── error.cpp ├── error.hpp ├── etrace_cat.c ├── exec_worker.py ├── filedeps.cpp ├── ftdb.c ├── ftdb.h ├── ftdb_entry.h ├── ftdbmaps.cpp ├── gcc.py ├── generate.py ├── get_clang_comps.py ├── get_gcc_comps.py ├── ide.py ├── input_name.cpp ├── main.cpp ├── maps.c ├── maps.h ├── nfsdb.h ├── nfsdb_maps.cpp ├── parser.cpp ├── parser.hpp ├── phash.h ├── phash.txt ├── postprocess.py ├── pyetrace.c ├── pyetrace.h ├── pyftdb.c ├── pyftdb.h ├── strnstr.c ├── tags.hpp ├── utils.c ├── utils.h └── worker.cpp ├── cas ├── cas_server.py ├── clang-proc ├── 10 │ ├── DeclPrinter.cpp │ ├── StmtPrinter.cpp │ └── TypePrinter.cpp ├── 11 │ ├── DeclPrinter.cpp │ ├── StmtPrinter.cpp │ └── TypePrinter.cpp ├── 12 │ ├── DeclPrinter.cpp │ ├── StmtPrinter.cpp │ └── TypePrinter.cpp ├── 13 │ ├── DeclPrinter.cpp │ ├── StmtPrinter.cpp │ └── TypePrinter.cpp ├── 14 │ ├── DeclPrinter.cpp │ ├── StmtPrinter.cpp │ └── TypePrinter.cpp ├── 15 │ ├── DeclPrinter.cpp │ ├── StmtPrinter.cpp │ └── TypePrinter.cpp ├── 16 │ ├── DeclPrinter.cpp │ ├── StmtPrinter.cpp │ └── TypePrinter.cpp ├── 17 │ ├── DeclPrinter.cpp │ ├── StmtPrinter.cpp │ └── TypePrinter.cpp ├── LICENSE ├── LICENSE.txt ├── MacroHandler.cpp ├── MacroHandler.h ├── README.md ├── base64.cpp ├── base64.h ├── compat.h ├── create_json_db ├── dbjson.cpp ├── dbjson.hpp ├── dbtaint.json ├── deref.md ├── json.hpp ├── jsonast.py ├── lookup.cpp ├── main.cc ├── main.hpp ├── notice.cpp ├── printers.h ├── sha.cpp ├── sha.h ├── taint.cpp ├── typehash.cpp ├── utils.cc ├── utils.h ├── visit.cpp ├── vmlinux-additional_defs.json └── vmlinux-macro_replacement.json ├── client ├── README.md ├── __init__.py ├── argparser.py ├── cmdline.py ├── exceptions.py ├── filtering.py ├── ftdb_generator │ ├── __init__.py │ └── ftdb_generator.py ├── ide_generator │ ├── __init__.py │ ├── generator_eclipse.py │ └── project_generator.py ├── misc.py ├── mod_base.py ├── mod_compilation.py ├── mod_dbops.py ├── mod_dependencies.py ├── mod_executables.py ├── mod_funcs.py ├── mod_globals.py ├── mod_misc.py ├── mod_modules.py ├── mod_opened_files.py ├── mod_sources.py ├── output_renderers │ ├── __init__.py │ ├── output.py │ ├── output_json.py │ └── output_plain.py ├── static │ ├── deps.js │ ├── deps_modal.js │ ├── main.js │ ├── modal.js │ ├── revdeps.js │ ├── revdeps_modal.js │ └── style.css ├── templates │ ├── deps_tree.html │ ├── layout.html │ ├── proc_tree.html │ └── revdeps_tree.html ├── test_ftdb.py └── test_main.py ├── docs ├── Makefile ├── make.bat └── source │ ├── client.rst │ ├── conf.py │ ├── index.rst │ └── libcas.rst ├── etrace ├── etrace_install.sh ├── etrace_sudoers ├── examples ├── build-avdkernel.sh ├── clean-avdkernel.sh ├── clone-avdkernel.sh ├── etrace_show_info ├── extract-avdkernel-info-for-ftdb ├── extract-cas-info-for-ftdb ├── ftdb_show_info ├── generate-pdf-files-for-all-modules ├── generate-pdf-files-for-kernel └── generate-pdf-files-for-ot ├── libcas.py ├── libft_db.py ├── setup.py ├── setup_etrace.sh ├── tests ├── ftdb_cache_test ├── ftdb_memory_test ├── ftdb_sha256_test.c └── ftdb_sha256_test.py ├── tools ├── bash_completion │ └── cas_completion.sh ├── nfsdb_compare.py └── virtual_environment │ ├── README.md │ └── img_build.sh ├── tracer ├── LICENSE ├── LICENSE.txt ├── Makefile ├── OUTPUT.md ├── README.md ├── bas_tracer.c ├── tests │ ├── execve │ │ └── execveat_test.c │ ├── ignore_opens │ │ ├── build.sh │ │ ├── invalid_close.c │ │ ├── mixed_opens.c │ │ ├── mixed_opens_interleaved.c │ │ ├── open16_close_open.c │ │ ├── open_close_interleaved.c │ │ ├── open_close_reversed.c │ │ └── open_close_seq.c │ ├── open │ │ └── multiple_opens.c │ └── thread_name │ │ ├── comm.c │ │ └── comm_pthread.c └── trie.h └── typings ├── libetrace.pyi └── libftdb.pyi /.gitignore: -------------------------------------------------------------------------------- 1 | *.ko.cmd 2 | *.mod.cmd 3 | *.o.cmd 4 | *.ko 5 | *.mod 6 | *.mod.c 7 | *.o 8 | *.so 9 | modules.order 10 | 11 | # Folders with build results 12 | /build*/ 13 | __pycache__/ 14 | *.pyc 15 | *.symvers 16 | 17 | # CMD files 18 | *symvers.cmd 19 | *order.cmd 20 | 21 | # vscode dir 22 | .vscode 23 | 24 | .pytest_cache 25 | llvm.sh 26 | 27 | # installed build 28 | cati 29 | etrace_parser 30 | worker 31 | clang-proc/clang-proc -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "kflat"] 2 | path = kflat 3 | url = https://github.com/Samsung/kflat 4 | -------------------------------------------------------------------------------- /CLIENT.md: -------------------------------------------------------------------------------- 1 | ## CAS client applications 2 | 3 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Engineers responsible for this project were: 2 | 3 | * Bartosz Zator 4 | Main contributor for this project. Created original code of BAS and FTDB processor. Technically and organizationally managed the project throughout its history. 5 | 6 | * Krystian Kieczka 7 | Developed low overhead version of the tracer based on Linux tracing infrastructure. Made the underlying tracing technology practically unnoticeable for most builds. 8 | 9 | * Mateusz Mańko 10 | Took over FTDB processor development. Substantially refactored existing code base and made groundwork for future FTDB support for C++ language. 11 | 12 | * Paweł Wieczorek 13 | Reworked post processing of clang compilation commands. Cut down the process from several hours to several minutes for entire Android platform build probably setting-up new world record in performance improvement over existing implementation. 14 | 15 | However, the project wouldn't have been possible without the ideas, support and bug reports from: 16 | Adrian Nieć - built entire infrastructure around the CAS which shaped all the existing (and non-existing) features of CAS. 17 | Tomasz Kuchta - developed AoT project (https://github.com/Samsung/auto_off_target) which proved to be the best way of testing the entire CAS infrastructure. 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Code Aware Services (CAS) 2 | Copyright (C) 2022 Samsung Electronics Co., Ltd. 3 | 4 | Unless otherwise stated, the files in the bas directory may be 5 | distributed under the terms of the GNU General Public License version 2. 6 | Please see the bas/LICENSE file for details. 7 | 8 | Unless otherwise stated, the files in the tracer directory may be 9 | distributed under the terms of the GNU General Public License version 2. 10 | Please see the tracer/LICENSE file for details. 11 | 12 | Rest of the files can be distributed under Apache License, Version 2.0. 13 | Please see clang-proc/LICENSE file for details. 14 | 15 | Licensed under the Apache License, Version 2.0 (the "License"); 16 | you may not use this file except in compliance with the License. 17 | You may obtain a copy of the License at 18 | 19 | http://www.apache.org/licenses/LICENSE-2.0 20 | 21 | Unless required by applicable law or agreed to in writing, software 22 | distributed under the License is distributed on an "AS IS" BASIS, 23 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | See the License for the specific language governing permissions and 25 | limitations under the License. 26 | -------------------------------------------------------------------------------- /bas/.bas_config: -------------------------------------------------------------------------------- 1 | { 2 | "ld_spec": [ 3 | "ld", 4 | "*/ld", 5 | "*-ld", 6 | "ld.gold", 7 | "*/ld.gold", 8 | "*-ld.gold", 9 | "ld.lld", 10 | "*/ld.lld", 11 | "*-ld.lld", 12 | "ld.lld-[0-9][0-9]", 13 | "*/ld.lld-[0-9][0-9]", 14 | "*-ld.lld-[0-9][0-9]", 15 | "*-link", 16 | "*/armlink" 17 | ], 18 | "ar_spec": [ 19 | "ar", 20 | "*/ar", 21 | "*-ar", 22 | "*/armar" 23 | ], 24 | "gcc_spec": [ 25 | "*gcc", 26 | "*gcc.real", 27 | "*gcc-[0-9].[0-9]", 28 | "*gcc-[0-9].[0-9].real", 29 | "*gcc-[0-9]", 30 | "*gcc-[0-9].real", 31 | "*gcc-[0-9][0-9]", 32 | "*gcc-[0-9][0-9].real" 33 | ], 34 | "gpp_spec": [ 35 | "*/g++", 36 | "*-g++", 37 | "*/g++.real", 38 | "*-g++.real", 39 | "*/g++-[0-9].[0-9]", 40 | "*-g++-[0-9].[0-9]", 41 | "*/g++-[0-9].[0-9].real", 42 | "*-g++-[0-9].[0-9].real", 43 | "*/g++-[0-9]", 44 | "*-g++-[0-9]", 45 | "*/g++-[0-9].real", 46 | "*-g++-[0-9].real", 47 | "*/g++-[0-9][0-9]", 48 | "*-g++-[0-9][0-9]", 49 | "*/g++-[0-9][0-9].real", 50 | "*-g++-[0-9][0-9].real" 51 | ], 52 | "clang_spec": [ 53 | "*clang", 54 | "*clang.real", 55 | "*clang-[0-9].[0-9]", 56 | "*clang-[0-9]", 57 | "*clang-[0-9].[0-9].real", 58 | "*clang-[0-9].real", 59 | "*clang-[0-9][0-9]", 60 | "*clang-[0-9][0-9].real" 61 | ], 62 | "clangpp_spec": [ 63 | "*clang++", 64 | "*clang++.real", 65 | "*clang++-[0-9].[0-9]", 66 | "*clang++-[0-9]", 67 | "*clang++-[0-9].[0-9].real", 68 | "*clang++-[0-9].real", 69 | "*clang++-[0-9][0-9]", 70 | "*clang++-[0-9][0-9].real" 71 | ], 72 | "armcc_spec": [ 73 | "*armcc" 74 | ], 75 | "clang_tailopts": [ 76 | "-fwhole-program-vtables", 77 | "-faddrsig", 78 | "-fno-c++-static-destructors", 79 | "-undef", 80 | "-fsplit-lto-unit" 81 | ], 82 | "integrated_clang_compilers": [ 83 | "/usr/lib/llvm-10/bin/clang" 84 | ], 85 | "rbm_wrapping_binaries": [ 86 | "/bin/bash", 87 | "/bin/sh", 88 | "/usr/bin/bash", 89 | "/usr/bin/sh" 90 | ], 91 | "dependency_exclude_patterns": [ 92 | "/dev/*", 93 | "/proc/*" 94 | ], 95 | "additional_module_exclude_patterns": [ 96 | ], 97 | "additional_module_exclude_pattern_variants": { 98 | }, 99 | "exclude_command_variants": { 100 | }, 101 | "module_dependencies_with_pipes":[ 102 | ], 103 | "module_dependencies_exclude_with_pipes":[ 104 | ] 105 | } 106 | -------------------------------------------------------------------------------- /bas/LICENSE: -------------------------------------------------------------------------------- 1 | Build Awareness Service (BAS), 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 | 16 | strnstr implementation was taken from the FreeBSD project: 17 | Copyright (c) 1992-2013 The FreeBSD Project. All rights reserved. 18 | and might be distributed under the license stated thereof. 19 | Please see strnstr.c file for details. 20 | 21 | cat source code (before modification) was taken from the GNU Coreutils 6.9 22 | and therefore might be distributed under GNU General Public License v.2 23 | or any later version. 24 | 25 | json_escape implementation (before modification) was taken from the SimpleJSON 26 | library (https://github.com/nbsdx/SimpleJSON.git) and therefore might be distributed 27 | under the WTFPL license (please see utils.c file). 28 | 29 | safe_rd implementation (before modification) was taken from the GNU CoreUtils 6.9 30 | and therefore might be distributed under the GNU General Public License v.2 or 31 | any later version (please see utils.c file). 32 | 33 | normpath implementation was taken from the following GitHub gist 34 | (https://gist.github.com/starwing/2761647) 35 | It was used by getting an explicit written consent from the author. 36 | 37 | Base 64 encoding/decoding utilities were taken from the GNOME Glib library 38 | and therefore might be distributed under the GNU Lesser General Public License v2.1. 39 | Please see base64.c file for details. 40 | 41 | Generic vector implementation was taken from the klib library (https://github.com/attractivechaos/klib) 42 | and therefore might te distributed under the MIT license. Please see klib.h file for details. 43 | 44 | C string format parsing function was taken from the Linux kernel source tree and therefore might be distributed 45 | under GNU General Public License v.2 or any later version. Please see utils.c file for details. 46 | 47 | Rich compare snippet for Python objects was taken from the Python 3.8 source code which is GPL compatible 48 | and therefore might be distributed under the PSF License Agreement. Please see utils.h file for details. 49 | 50 | C++ thread pool implementation comes from https://github.com/bshoshany/thread-pool by Barak Shoshany. 51 | 52 | Copyright (c) 2022 Barak Shoshany 53 | 54 | Permission is hereby granted, free of charge, to any person obtaining a copy 55 | of this software and associated documentation files (the "Software"), to deal 56 | in the Software without restriction, including without limitation the rights 57 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 58 | copies of the Software, and to permit persons to whom the Software is 59 | furnished to do so, subject to the following conditions: 60 | 61 | The above copyright notice and this permission notice shall be included in all 62 | copies or substantial portions of the Software. 63 | -------------------------------------------------------------------------------- /bas/armcc.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.dont_write_bytecode = True 3 | 4 | import os 5 | import re 6 | import subprocess 7 | import libetrace 8 | import string 9 | 10 | COMPILER_NONE = 0 11 | COMPILER_C = 1 12 | COMPILER_CPP = 2 13 | 14 | class armcc(libetrace.armcc): 15 | 16 | def __init__(self,verbose,debug,debug_compilations=False): 17 | super(armcc, self).__init__(verbose,debug,debug_compilations) 18 | 19 | def compiler_type(self,cbin): 20 | return COMPILER_NONE 21 | 22 | def compiler_include_paths(self,cbin): 23 | return None 24 | 25 | def parse_include_files(self,exe,ipaths): 26 | cmd = exe[2] 27 | ifiles = list() 28 | include_opt_indices = [i for i, x in enumerate(cmd) if x.startswith("--preinclude")] 29 | for i in include_opt_indices: 30 | if "=" in cmd[i]: 31 | val = "=".join(cmd[i].split("=")[1:]) 32 | else: 33 | val = cmd[i+1] 34 | if os.path.isabs(val): 35 | ifiles.append(val) 36 | else: 37 | tryPaths = [os.path.normpath(os.path.join(x,cmd[i+1])) for x in ipaths]+[os.path.realpath(os.path.normpath(os.path.join(exe[1],cmd[i+1])))] 38 | pathsExist = [x for x in tryPaths if os.path.isfile(x)] 39 | if (len(pathsExist)>0): 40 | ifiles.append(pathsExist[0]) 41 | return ifiles 42 | 43 | def get_compiled_files(self,out,exe): 44 | return [ flst.split("\n")[0].split()[2].strip("\"") for flst in out[0] ] 45 | 46 | def get_object_files(self,comp_exe,fork_map,rev_fork_map,wr_map): 47 | return [] 48 | 49 | def parse_defs(self,out,exe): 50 | 51 | def path_to_include(include_line): 52 | if len(include_line.strip())<=0 or include_line[0]!="N": 53 | return None 54 | include_line = (" " + include_line[1:]).strip()[1:].strip().split() 55 | if include_line[0]!="include": 56 | return None 57 | iline = include_line[1] 58 | if "<" in iline and ">" in iline or "\"" in iline: 59 | return include_line[1].strip("<").strip(">").strip("\"") 60 | else: 61 | return None 62 | 63 | idirs = set() 64 | cwd = exe[1] 65 | for outv in out[0]: 66 | prevline = "" 67 | for line in outv.split("\n")[1:]: 68 | if line.startswith("L") and int(line.split()[-1])==1: 69 | iline = line.split()[-2].strip("\"") 70 | ipath = path_to_include(prevline) 71 | if ipath: 72 | ipath = os.path.normpath(ipath) 73 | if not iline.startswith("/"): 74 | iline = os.path.join(cwd,iline) 75 | ilines = iline.split("/") 76 | for u in reversed(ipath.split("/")): 77 | if u==".": 78 | pass 79 | elif u=="..": 80 | start_dir = "/".join(ilines) 81 | subdirs = [x for x in os.listdir(start_dir) if os.path.isdir(os.path.join(start_dir,x))] 82 | if len(subdirs)>0: 83 | ilines.append(subdirs[0]) 84 | else: 85 | if u!=ilines[-1]: 86 | print ("include (%s) not at (%s)"%(u,iline)) 87 | ilines = ilines[:-1] 88 | idirs.add("/".join(ilines)) 89 | else: 90 | ils = iline.split("/")[:-1] 91 | if len(ils)>0: 92 | if ils[0]=="": 93 | idirs.add("/".join(ils)) 94 | else: 95 | idirs.add(os.path.join(cwd,"/".join(ils))) 96 | else: 97 | idirs.add(cwd) 98 | prevline = line 99 | includes = list(idirs) 100 | 101 | def parse_one_def(s): 102 | st = set(string.whitespace) 103 | i = next((i for i, ch in enumerate(s) if ch in st),None) 104 | if i: 105 | return (s[:i],s[i:].strip()) 106 | else: 107 | return (s,"") 108 | 109 | defs = [parse_one_def(x[7:].lstrip()) for x in out[1].split("\n") if x.startswith("#define")] 110 | undefs = [parse_one_def(x[6:].lstrip()) for x in out[1].split("\n") if x.startswith("#undef")] 111 | return (includes,defs,undefs) 112 | 113 | def get_source_type(self,cmd,compiler_type,src_ext): 114 | 115 | if "--cpp" in cmd or "--cpp11" in cmd: 116 | return COMPILER_CPP 117 | if "--c90" in cmd or "--c99" in cmd: 118 | return COMPILER_C 119 | 120 | if compiler_type==COMPILER_CPP: 121 | return COMPILER_CPP 122 | else: 123 | if src_ext in [".c",".ac",".tc"]: 124 | return COMPILER_C 125 | else: 126 | return COMPILER_CPP 127 | -------------------------------------------------------------------------------- /bas/compiler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #define __USE_XOPEN_EXTENDED 7 | #include 8 | #include "compiler.h" 9 | 10 | #ifdef __USE_GNU 11 | #define var_environ environ 12 | #else 13 | #define var_environ __environ 14 | #endif 15 | 16 | unsigned long progress_max_g; 17 | unsigned long progress_g; 18 | 19 | int run_child(const char* bin, const char* cwd, PyObject* args, int* pfd, int child_read_fd) { 20 | 21 | /* 22 | * Check cwd points to the valid directory 23 | */ 24 | DIR* dir = opendir(cwd); 25 | if (dir == NULL) 26 | return -1; 27 | closedir(dir); 28 | 29 | /* 30 | * So basically, this whole block just checks whether bin exists? 31 | * is it neccessary? I mean, we are only running clang here anyway... 32 | */ 33 | // char* current_wd = getcwd(0, 0); 34 | // if (chdir(cwd)<0) { 35 | // free(current_wd); 36 | // return -1; 37 | // } 38 | 39 | // int ra = access(bin, F_OK | X_OK); 40 | // if (ra) { 41 | // free(current_wd); 42 | // return -1; 43 | // } 44 | 45 | // chdir(current_wd); 46 | // free(current_wd); 47 | 48 | 49 | /* 50 | * Do some magic pipes trickery 51 | */ 52 | int fd[2]; 53 | int fdr[2]; 54 | int r = pipe(fd); 55 | if (r<0) return r; 56 | if (child_read_fd) { 57 | int r = pipe(fdr); 58 | if (r<0) return r; 59 | } 60 | pid_t pid = fork(); 61 | if (pid > 0) { 62 | /* We're at the parent */ 63 | close(fd[1]); 64 | if (child_read_fd) { 65 | close(fdr[0]); 66 | close(fdr[1]); 67 | } 68 | } 69 | else if (pid == 0) { 70 | /* Hello child! */ 71 | char** argv = malloc((PyList_Size(args)+1)*sizeof(const char*)); 72 | Py_ssize_t u; 73 | for (u=0; u 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "tags.hpp" 18 | 19 | class AbstractError { 20 | private: 21 | static char m_identifier; 22 | protected: 23 | std::string m_error_message; 24 | public: 25 | virtual ~AbstractError() = default; 26 | 27 | std::string_view explain(void) { 28 | return m_error_message; 29 | } 30 | 31 | static const void *identifier() { 32 | return &m_identifier; 33 | } 34 | 35 | template 36 | bool compare_to() { 37 | return identifier() == T::identifier(); 38 | } 39 | }; 40 | 41 | template 42 | class BasicError : public AbstractError { 43 | public: 44 | using AbstractError::AbstractError; 45 | 46 | static const void *identifier() { 47 | return &T::m_identifier; 48 | } 49 | }; 50 | 51 | class BadSeparatorError : public BasicError { 52 | public: 53 | BadSeparatorError(size_t line_number, const char *line) { 54 | m_error_message = "err: No separator on line " + std::to_string(line_number) + ": " + line + '\n'; 55 | } 56 | 57 | static char m_identifier; 58 | }; 59 | 60 | class IntegerParseError : public BasicError { 61 | private: 62 | static char m_identifier; 63 | public: 64 | IntegerParseError(size_t line_number, const char *line, int err_num) { 65 | m_error_message = "err: Error while parsing an integer on line " + std::to_string(line_number) 66 | + " " + std::strerror(err_num) + ": " + line + "\n"; 67 | } 68 | }; 69 | 70 | class BadFormatError : public BasicError { 71 | public: 72 | BadFormatError(size_t line_number) 73 | { 74 | m_error_message = "err: Invalid format on line: " + std::to_string(line_number) + "\n"; 75 | } 76 | 77 | static char m_identifier; 78 | }; 79 | 80 | class UnexpectedArgumentEndError : public BasicError { 81 | public: 82 | UnexpectedArgumentEndError(size_t line_number) 83 | { 84 | m_error_message = "err: Unexpected end of arguments on line: " + std::to_string(line_number) + "\n"; 85 | } 86 | 87 | static char m_identifier; 88 | }; 89 | 90 | class SizeMismatchError : public BasicError { 91 | public: 92 | SizeMismatchError(size_t line_number, size_t got, size_t expected) 93 | { 94 | m_error_message = "err: Size mismatch on line " + 95 | std::to_string(line_number) + ": expected " + std::to_string(expected) + " got " + 96 | std::to_string(got) + '\n'; 97 | } 98 | }; 99 | 100 | class UnexpectedTagError : public BasicError { 101 | public: 102 | UnexpectedTagError(size_t line_number, Tag tag) 103 | { 104 | (void) tag; 105 | m_error_message = "err: Expected different tag on line " + std::to_string(line_number) + '\n'; 106 | } 107 | 108 | UnexpectedTagError(size_t line_number, ShortArguments tag) 109 | { 110 | (void) tag; 111 | m_error_message = "err: Expected different tag on line " + std::to_string(line_number) + '\n'; 112 | } 113 | 114 | static char m_identifier; 115 | }; 116 | 117 | template 118 | class Errorable { 119 | friend Errorable; 120 | private: 121 | std::unique_ptr m_value_ptr; 122 | std::unique_ptr m_error_ptr; 123 | bool m_error; 124 | public: 125 | Errorable() = default; 126 | Errorable(T t) 127 | : m_value_ptr (std::make_unique(std::move(t))) 128 | , m_error_ptr () 129 | , m_error (false) 130 | {}; 131 | 132 | template 133 | Errorable(U u) 134 | : m_value_ptr () 135 | , m_error_ptr (std::make_unique(std::move(u))) 136 | , m_error (true) 137 | {}; 138 | 139 | Errorable(Errorable const& other) = delete; 140 | 141 | template 142 | Errorable(Errorable&& other) 143 | : m_value_ptr () 144 | , m_error_ptr (std::move(other.m_error_ptr)) 145 | , m_error (true) 146 | {}; 147 | 148 | Errorable(Errorable&& other) = default; 149 | 150 | ~Errorable() = default; 151 | 152 | std::string_view explain(void) const { 153 | if (!m_error) 154 | throw std::bad_optional_access(); 155 | 156 | return m_error_ptr->explain(); 157 | }; 158 | 159 | bool is_error(void) { 160 | return m_error; 161 | }; 162 | 163 | T& value(void) { 164 | if (m_error || !m_value_ptr.get()) 165 | throw std::bad_optional_access(); 166 | 167 | return *m_value_ptr; 168 | }; 169 | }; 170 | 171 | template <> 172 | class Errorable { 173 | private: 174 | std::unique_ptr m_error_ptr; 175 | bool m_error; 176 | public: 177 | Errorable() = default; 178 | 179 | template 180 | Errorable(T t) 181 | : m_error_ptr (std::make_unique(std::move(t))) 182 | , m_error (true) 183 | {}; 184 | 185 | Errorable(Errorable const& other) = delete; 186 | 187 | template 188 | Errorable(Errorable&& other) 189 | : m_error_ptr (std::move(other.m_error_ptr)) 190 | , m_error (true) 191 | {}; 192 | 193 | ~Errorable() = default; 194 | 195 | std::string_view explain(void) const { 196 | if (!m_error || !m_error_ptr.get()) 197 | throw std::bad_optional_access(); 198 | 199 | return m_error_ptr->explain(); 200 | }; 201 | 202 | bool is_error(void) { 203 | return m_error; 204 | }; 205 | 206 | void value(void) { 207 | throw std::bad_optional_access(); 208 | }; 209 | }; 210 | -------------------------------------------------------------------------------- /bas/exec_worker.py: -------------------------------------------------------------------------------- 1 | """ 2 | exec_worker.py - library used for controlling BAS fork server process 3 | """ 4 | import os 5 | import subprocess 6 | import struct 7 | 8 | from typing import List, Tuple, Optional 9 | 10 | 11 | ############################### 12 | # Execution worker library 13 | ############################### 14 | class ExecWorkerException(Exception): 15 | pass 16 | 17 | 18 | class ExecWorker: 19 | initialized: bool = False 20 | 21 | def __init__(self, workerPath: str = "./worker"): 22 | self.workerPath = workerPath 23 | self.initialize() 24 | 25 | def __del__(self): 26 | self.destroy() 27 | 28 | 29 | """ Read precisely `size` bytes from provided file descriptors 30 | Used to handle partial reads than can occur when using os.read 31 | """ 32 | def _safe_read(self, fd: int, size: int) -> bytes: 33 | data = b"" 34 | while size > 0: 35 | part = os.read(fd, size) 36 | size -= len(part) 37 | data += part 38 | return data 39 | 40 | """ Writes precisely `size` bytes to the provided FD 41 | Used for the same reason as _safe_read 42 | """ 43 | def _safe_write(self, fd: int, buf: bytes) -> None: 44 | offset = 0 45 | while offset < len(buf): 46 | part = os.write(fd, buf[offset:]) 47 | offset += part 48 | 49 | 50 | def initialize(self) -> None: 51 | self.pRead, self.pChildWrite = os.pipe() 52 | self.pChildRead, self.pWrite = os.pipe() 53 | self.worker = subprocess.Popen([self.workerPath, str(self.pChildRead), str(self.pChildWrite)], 54 | shell=False, pass_fds=(self.pChildRead, self.pChildWrite)) 55 | 56 | os.close(self.pChildRead) 57 | os.close(self.pChildWrite) 58 | self.initialized = True 59 | 60 | worker_status = self.worker.poll() 61 | if worker_status is not None: 62 | self.destroy() 63 | raise ExecWorkerException(f"Worker process has terminated unexpectedly with error code {worker_status}") 64 | 65 | 66 | def destroy(self) -> None: 67 | if not self.initialized: 68 | return 69 | 70 | os.close(self.pWrite) 71 | os.close(self.pRead) 72 | self.worker.kill() 73 | self.initialized = False 74 | 75 | 76 | def runCmd(self, cwd: str, cmd: str, args: List[str], input: Optional[str] = None) -> Tuple[str, str, int]: 77 | worker_status = self.worker.poll() 78 | if worker_status is not None: 79 | self.destroy() 80 | raise ExecWorkerException(f"Cannot run command - worker exited with error code {worker_status}") 81 | 82 | if input is None: 83 | input = "" 84 | 85 | # Send command to worker 86 | bCwd = cwd.encode() 87 | bInput = input.encode() 88 | dataToSend = struct.pack("III", len(bCwd), len(bInput), len(args) + 1) 89 | dataToSend += bCwd 90 | dataToSend += bInput 91 | for arg in [cmd, *args]: 92 | bArg = arg.encode() 93 | dataToSend += struct.pack("I", len(bArg)) 94 | dataToSend += bArg 95 | self._safe_write(self.pWrite, dataToSend) 96 | 97 | # Hang on pipe read and retrieve output 98 | header = self._safe_read(self.pRead, 14) 99 | sizeOut, sizeErr, retCode, error = struct.unpack("IIiH", header) 100 | dataOut = self._safe_read(self.pRead, sizeOut) 101 | dataErr = self._safe_read(self.pRead, sizeErr) 102 | 103 | if error: 104 | self.destroy() 105 | raise ExecWorkerException(f"Cannot run command - worker encountered an error {dataErr.decode()}") 106 | return dataOut.decode(), dataErr.decode(), retCode 107 | -------------------------------------------------------------------------------- /bas/ftdb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include "ftdb.h" 9 | 10 | struct ftdb_c { 11 | bool init_done; 12 | int verbose; 13 | int debug; 14 | const struct ftdb* ftdb; 15 | CUnflatten unflatten; 16 | }; 17 | 18 | #define FTDB_C_TYPE(ftdb_c) ((struct ftdb_c*)ftdb_c) 19 | 20 | CFtdb libftdb_c_ftdb_load(const char* filename, int quiet, int debug) { 21 | 22 | bool err = true; 23 | 24 | struct ftdb_c* ftdb_c = malloc(sizeof(struct ftdb_c)); 25 | ftdb_c->verbose = !quiet; 26 | ftdb_c->debug = debug; 27 | 28 | FILE* in = fopen(filename, "r+b"); 29 | if(!in) { 30 | in = fopen(filename, "rb"); 31 | if(!in) { 32 | fprintf(stderr,"Cannot open cache file - (%d) %s\n", errno, strerror(errno)); 33 | goto done; 34 | } 35 | } 36 | 37 | int debug_level = 0; 38 | if(debug) debug_level = 2; 39 | else if(!quiet) debug_level = 1; 40 | 41 | ftdb_c->unflatten = unflatten_init(debug_level); 42 | if(ftdb_c->unflatten == NULL) { 43 | fprintf(stderr,"Failed to intialize unflatten library\n"); 44 | goto done; 45 | } 46 | 47 | if (unflatten_load_continuous(ftdb_c->unflatten, in, NULL)) { 48 | fprintf(stderr,"Failed to read cache file\n"); 49 | unflatten_deinit(ftdb_c->unflatten); 50 | goto done; 51 | } 52 | fclose(in); 53 | 54 | ftdb_c->ftdb = (const struct ftdb*) unflatten_root_pointer_next(ftdb_c->unflatten); 55 | 56 | /* Check whether it's correct file and in supported version */ 57 | if(ftdb_c->ftdb->db_magic != FTDB_MAGIC_NUMBER) { 58 | fprintf(stderr,"Failed to parse cache file - invalid magic %llu\n", ftdb_c->ftdb->db_magic); 59 | unflatten_deinit(ftdb_c->unflatten); 60 | goto done; 61 | } 62 | if(ftdb_c->ftdb->db_version != FTDB_VERSION) { 63 | fprintf(stderr,"Failed to parse cache file - unsupported image version %llu (required: %llu)\n", ftdb_c->ftdb->db_version, FTDB_VERSION); 64 | unflatten_deinit(ftdb_c->unflatten); 65 | goto done; 66 | } 67 | 68 | ftdb_c->init_done = true; 69 | err = false; 70 | 71 | done: 72 | if (err) { 73 | free(ftdb_c); 74 | return NULL; /* Indicate that exception has been set */ 75 | } 76 | 77 | return ftdb_c; 78 | } 79 | 80 | void libftdb_c_ftdb_unload(CFtdb ftdb_c) { 81 | unflatten_deinit(FTDB_C_TYPE(ftdb_c)->unflatten); 82 | free(ftdb_c); 83 | } 84 | 85 | struct ftdb* libftdb_c_ftdb_object(CFtdb ftdb_c) { 86 | return (struct ftdb*)FTDB_C_TYPE(ftdb_c)->ftdb; 87 | } 88 | 89 | struct ftdb_type_entry* libftdb_c_get_type_entry_by_id(CFtdb ftdb_c, unsigned long id) { 90 | 91 | struct ulong_entryMap_node* node = ulong_entryMap_search(&FTDB_C_TYPE(ftdb_c)->ftdb->refmap, id); 92 | if (node) 93 | return (struct ftdb_type_entry*)node->entry; 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /bas/ftdbmaps.cpp: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | #include "pyftdb.h" 3 | #include "utils.h" 4 | } 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | /* 13 | Some precomputed maps 14 | refmap: type_id -> type entry 15 | hrefmap: type_hash -> type entry 16 | frefmap: func_id -> func_entry 17 | fhrefmap: func_hash -> func_entry 18 | fnrefmap: func_name -> [func_entry, func_entry...] 19 | grefmap: global_id -> global_entry 20 | ghrefmap: global_hash -> global_entry 21 | gnrefmap: global_name -> global_entry 22 | fdrefmap: fdecl_id -> func_decl_entry 23 | fdhrefmap: fdeclhash -> func_decl_entry 24 | fdnrefmap: fdeclname -> [func_decl_entry, func_decl_entry...] 25 | */ 26 | int ftdb_maps(struct ftdb* ftdb, int show_stats) { 27 | 28 | for (unsigned long i=0; itypes_count; ++i) { 29 | struct ftdb_type_entry* type_entry = &ftdb->types[i]; 30 | ulong_entryMap_insert(&ftdb->refmap,type_entry->id,type_entry); 31 | stringRef_entryMap_insert(&ftdb->hrefmap, type_entry->hash, type_entry); 32 | } 33 | 34 | printf("refmap keys: %zu\n",ulong_entryMap_count(&ftdb->refmap)); 35 | printf("hrefmap keys: %zu\n",stringRef_entryMap_count(&ftdb->hrefmap)); 36 | 37 | std::map> fnrefmap; 38 | for (unsigned long i=0; ifuncs_count; ++i) { 39 | struct ftdb_func_entry* func_entry = &ftdb->funcs[i]; 40 | ulong_entryMap_insert(&ftdb->frefmap,func_entry->id,func_entry); 41 | stringRef_entryMap_insert(&ftdb->fhrefmap, func_entry->hash, func_entry); 42 | fnrefmap[func_entry->name].push_back(func_entry); 43 | } 44 | 45 | printf("frefmap keys: %zu\n",ulong_entryMap_count(&ftdb->frefmap)); 46 | printf("fhrefmap keys: %zu\n",stringRef_entryMap_count(&ftdb->fhrefmap)); 47 | 48 | BUILD_STRINGREF_ENTRYLIST_MAP(ftdb,fnrefmap,fnrefmap); 49 | 50 | std::map> gnrefmap; 51 | for (unsigned long i=0; iglobals_count; ++i) { 52 | struct ftdb_global_entry* global_entry = &ftdb->globals[i]; 53 | ulong_entryMap_insert(&ftdb->grefmap,global_entry->id,global_entry); 54 | stringRef_entryMap_insert(&ftdb->ghrefmap, global_entry->hash, global_entry); 55 | gnrefmap[global_entry->name].push_back(global_entry); 56 | } 57 | 58 | printf("grefmap keys: %zu\n",ulong_entryMap_count(&ftdb->grefmap)); 59 | printf("ghrefmap keys: %zu\n",stringRef_entryMap_count(&ftdb->ghrefmap)); 60 | 61 | BUILD_STRINGREF_ENTRYLIST_MAP(ftdb,gnrefmap,gnrefmap); 62 | 63 | std::map> fdnrefmap; 64 | for (unsigned long i=0; ifuncdecls_count; ++i) { 65 | struct ftdb_funcdecl_entry* funcdecl_entry = &ftdb->funcdecls[i]; 66 | ulong_entryMap_insert(&ftdb->fdrefmap,funcdecl_entry->id,funcdecl_entry); 67 | stringRef_entryMap_insert(&ftdb->fdhrefmap, funcdecl_entry->declhash, funcdecl_entry); 68 | fdnrefmap[funcdecl_entry->name].push_back(funcdecl_entry); 69 | } 70 | printf("fdrefmap keys: %zu\n",ulong_entryMap_count(&ftdb->fdrefmap)); 71 | printf("fdhrefmap keys: %zu\n",stringRef_entryMap_count(&ftdb->fdhrefmap)); 72 | 73 | BUILD_STRINGREF_ENTRYLIST_MAP(ftdb,fdnrefmap,fdnrefmap); 74 | 75 | return 1; 76 | } 77 | -------------------------------------------------------------------------------- /bas/generate.py: -------------------------------------------------------------------------------- 1 | cdb_xml = """ 2 | 3 | %s""" 4 | 5 | link_template = """ 6 | %s 7 | %d 8 | %s 9 | """ 10 | 11 | filter_template = """ 12 | %d 13 | %s 14 | %d 15 | 16 | org.eclipse.ui.ide.multiFilter 17 | 1.0-name-matches-false-false-%s 18 | 19 | """ 20 | 21 | project_template = """ 22 | 23 | %s 24 | This file was autogenerated. Do not modify! 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 31 | clean,full,incremental, 32 | 33 | 34 | 35 | 36 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 37 | full,incremental, 38 | 39 | 40 | 41 | 42 | 43 | org.eclipse.cdt.core.cnature 44 | org.eclipse.cdt.core.ccnature 45 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 46 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 47 | 48 | 49 | %s 50 | 51 | %s 52 | 53 | """ 54 | 55 | cproject_template=""" 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | """ -------------------------------------------------------------------------------- /bas/get_clang_comps.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | import clang 3 | import pickle as cPickle 4 | import os 5 | import subprocess 6 | import libetrace 7 | import sys 8 | import traceback 9 | 10 | integrated_clang_compilers = [] 11 | clangxx_input_execs = [] 12 | 13 | def have_integrated_cc1(exe): 14 | return all([ 15 | "-fno-integrated-cc1" not in exe[2], 16 | os.path.realpath(os.path.normpath(os.path.join(exe[1], exe[0]))) in integrated_clang_compilers 17 | ]) 18 | 19 | def replace_cc1_executor(x): 20 | if not have_integrated_cc1((x["b"], x["w"], x["v"])): 21 | return { 22 | "b": x["b"], 23 | "w": x["w"], 24 | "v": x["v"], 25 | "p": x["p"], 26 | "x": x["x"], 27 | "t": x["t"], 28 | "i": 0 29 | } 30 | 31 | pn = None 32 | try: 33 | pn = subprocess.Popen( 34 | [x["b"]] + x["v"][1:] + ["-###"], 35 | cwd = x["w"], 36 | shell=False, 37 | stdin=subprocess.PIPE, 38 | stdout=subprocess.PIPE, 39 | stderr=subprocess.STDOUT 40 | ) 41 | out, err = pn.communicate("") 42 | except Exception: 43 | print("Exception while running clang -### commands:") 44 | print ("[%s] %s"%(x["w"]," ".join([x["b"]] + x["v"][1:] + ["-###"]))) 45 | traceback.print_exc(limit=0) 46 | 47 | if pn and pn.returncode == 0: 48 | lns = out.decode("utf-8").split("\n") 49 | idx = [k for k,u in enumerate(lns) if "(in-process)" in u] 50 | if idx and len(lns) >= idx[0] + 2: 51 | ncmd = lns[idx[0] + 1] 52 | try: 53 | return { 54 | "b": x["b"], 55 | "w": x["w"], 56 | "v": [ 57 | u[1:-1].encode('latin1').decode('unicode-escape').encode('latin1').decode('utf-8') 58 | for u in libetrace.parse_compiler_triple_hash(ncmd) 59 | ], 60 | "p": x["p"], 61 | "x": x["x"], 62 | "t": x["t"], 63 | "i": 1 64 | } 65 | except Exception as e: 66 | print ("Exception while replacing integrated clang invocation:") 67 | print ("Original command:") 68 | print (" %s [%s] %s"%(x["b"],x["w"]," ".join(x["v"]))) 69 | traceback.print_exc() 70 | return { 71 | "b": x["b"], 72 | "w": x["w"], 73 | "v": x["v"], 74 | "p": x["p"], 75 | "x": x["x"], 76 | "t": x["t"], 77 | "i": 0 78 | } 79 | 80 | 81 | def get_clang_comps(clangxx_input_execs, clang_tailopts, 82 | clang_compilers, clangpp_compilers, integrated_clang_compilers, start_offset, debug, verbose, debug_compilations, allow_pp_in_compilations, chunk_number ): 83 | 84 | clang_c = clang.clang(verbose,debug,clang_compilers,clangpp_compilers,integrated_clang_compilers,debug_compilations) 85 | 86 | result = {} 87 | for i in range(len(clangxx_input_execs)): 88 | new_exec = (clangxx_input_execs[i][0], clangxx_input_execs[i][1], clangxx_input_execs[i][2], clangxx_input_execs[i][3], clangxx_input_execs[i][5]) 89 | x = clang_c.get_compilations([new_exec], 1, tailopts=clang_tailopts, allowpp=allow_pp_in_compilations) 90 | if len(x) == 0: 91 | continue 92 | result[start_offset + i] = x[0] 93 | sys.stdout.write('\r-- get_clang_comps: done chunk %d' % (chunk_number)) 94 | return result 95 | 96 | 97 | def main(): 98 | global integrated_clang_compilers, clangxx_input_execs 99 | 100 | if len(sys.argv) < 2: 101 | sys.stderr.write("This tool is intented to be used only internally by wrapper script") 102 | exit(1) 103 | 104 | if 'clang' in sys.argv[1]: 105 | inFile = sys.argv[2] 106 | outFile = sys.argv[3] 107 | 108 | with open(inFile, 'rb') as f: 109 | args = cPickle.load(f) 110 | job_list = get_clang_comps(**args) 111 | 112 | with open(outFile, 'wb') as f: 113 | cPickle.dump(job_list, f) 114 | elif 'cc1_replace' in sys.argv: 115 | with open('cc1_replace.pkl','rb') as f: 116 | args = cPickle.load(f) 117 | 118 | integrated_clang_compilers = args["integrated_clang_compilers"] 119 | clangxx_input_execs = args["clangxx_input_execs"] 120 | 121 | print ("Replacing cc1 calls for integrated cc1 invocation ... (%d compilations; %d jobs)"%(len(clangxx_input_execs),multiprocessing.cpu_count())) 122 | p = multiprocessing.Pool(multiprocessing.cpu_count()) 123 | job_list = p.map(replace_cc1_executor, clangxx_input_execs) 124 | print('-- replace_cc1_executor: Done. Sharing results with parent process') 125 | 126 | with open('cc1_replace_result2.pkl', 'wb') as f: 127 | cPickle.dump(job_list, f) 128 | 129 | if __name__ == '__main__': 130 | main() 131 | -------------------------------------------------------------------------------- /bas/get_gcc_comps.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | import gcc 3 | import pickle as cPickle 4 | import os 5 | import subprocess 6 | import libetrace 7 | import sys 8 | import traceback 9 | 10 | gxx_input_execs = [] 11 | 12 | def get_gcc_comps(gxx_input_execs, 13 | gcc_compilers, gpp_compilers, start_offset, debug, verbose, debug_compilations, input_compiler_parser, chunk_number ): 14 | 15 | gcc_c = gcc.gcc(verbose,debug,gcc_compilers,gpp_compilers,debug_compilations) 16 | 17 | plugin_path = os.path.join(os.path.dirname(sys.argv[0]),"../libgcc_input_name.so") 18 | plugin_path = "-fplugin=" + os.path.realpath(plugin_path) 19 | 20 | result = {} 21 | for i in range(len(gxx_input_execs)): 22 | new_exec = (gxx_input_execs[i][0], gxx_input_execs[i][1], gxx_input_execs[i][2], gxx_input_execs[i][3]) 23 | if input_compiler_parser is None: 24 | x = gcc_c.get_compilations([new_exec],1,plugin_path) 25 | else: 26 | x = gcc_c.get_compilations([new_exec],1,plugin_path,input_compiler_parser) 27 | if len(x) == 0: 28 | continue 29 | result[start_offset + i] = x[0] 30 | sys.stdout.write('\r-- get_gcc_comps: done chunk %d' % (chunk_number)) 31 | return result 32 | 33 | 34 | def main(): 35 | global gxx_input_execs 36 | 37 | if len(sys.argv) < 2: 38 | sys.stderr.write("This tool is intented to be used only internally by wrapper script") 39 | exit(1) 40 | 41 | if 'gcc' in sys.argv[1]: 42 | inFile = sys.argv[2] 43 | outFile = sys.argv[3] 44 | 45 | with open(inFile, 'rb') as f: 46 | args = cPickle.load(f) 47 | job_list = get_gcc_comps(**args) 48 | 49 | with open(outFile, 'wb') as f: 50 | cPickle.dump(job_list, f) 51 | 52 | if __name__ == '__main__': 53 | main() 54 | -------------------------------------------------------------------------------- /bas/ide.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import json 4 | import re 5 | import sys 6 | 7 | class APGN(object): 8 | 9 | def __init__(self,nfsdb): 10 | self.nfsdb = nfsdb 11 | self.cmap = {} 12 | h = re.compile("^/dev/.*") 13 | for e in nfsdb: 14 | if e.has_compilations(): 15 | for cf in e.compilation_info.file_paths: 16 | if not h.match(cf): 17 | if cf not in self.cmap: 18 | self.cmap[cf] = [e] 19 | else: 20 | self.cmap[cf].append(e) 21 | 22 | def path_under_root(self,path,root): 23 | path_components = iter(path.split(os.sep)[1:]) 24 | current_path = "" 25 | original_root = "" 26 | for pc in path_components: 27 | current_path+=os.sep+pc 28 | if os.path.islink(current_path): 29 | current_path = os.path.normpath(os.readlink(current_path)) 30 | original_root+=os.sep+pc 31 | if current_path==root: 32 | return os.sep.join([u for u in path_components]), original_root 33 | return None,None 34 | 35 | def generate_project_description_files(self, 36 | project_files_list, 37 | module_name, 38 | dep_pids, 39 | source_root, 40 | outdir, 41 | verbose=False, 42 | debug=False, 43 | quiet=False): 44 | 45 | pflst = list() 46 | lnklst = list() 47 | symlst = list() 48 | real_root = os.path.realpath(source_root) 49 | nroot = os.path.join(os.path.realpath(outdir),source_root.split(os.sep)[-1]) 50 | for fn in project_files_list: 51 | if not self.nfsdb.path_regular(fn) and not self.nfsdb.path_symlinked(fn): 52 | continue 53 | if self.nfsdb.path_symlinked(fn): 54 | # Save the list of original paths accessed through the symlinks (need to be copied as well) 55 | symlst+=[os.path.normpath(x) for x in self.nfsdb.symlink_paths(fn) if os.path.exists(x)] 56 | pfn,original_root = self.path_under_root(fn,real_root) 57 | if pfn: 58 | if os.path.exists(fn): 59 | if len(pfn)>0: 60 | pflst.append( (pfn,original_root) ) 61 | 62 | symlst = list(set(symlst)) 63 | for fn in symlst: 64 | lnk = os.readlink(fn) 65 | if os.path.isabs(lnk): 66 | # Resolve the link to the new location 67 | lnk.replace(source_root,nroot) 68 | pfn,original_root = self.path_under_root(fn,real_root) 69 | if pfn: 70 | if len(pfn)>0: 71 | lnklst.append( (pfn,original_root,lnk) ) 72 | 73 | compilation_executions = list() 74 | compiled_files = set() 75 | for pf in pflst: 76 | pfpath = os.path.join(pf[1],pf[0]) 77 | if pfpath in self.cmap: 78 | compilation_executions+=self.cmap[pfpath] 79 | compiled_files.add(pfpath) 80 | 81 | # Extract all referenced files by all compilation executions 82 | all_compiler_references = set() 83 | for ce in compilation_executions: 84 | ce_all = self.nfsdb[(ce.eid.pid,)] 85 | for this_ce in ce_all: 86 | all_compiler_references|=this_ce.openpaths_with_children 87 | 88 | # Add special macro that is only available at IDE 89 | # X.append(("__BAS__IDE_PROJECT_GENERATOR__","")) 90 | 91 | def json_command(cmd): 92 | return " ".join([x.rstrip().replace("\\","\\\\").replace("\"","\\\"").replace(" ","\\ ") for x in cmd]) 93 | 94 | compile_commands=list() 95 | for pf in pflst: 96 | pfpath = os.path.join(pf[1],pf[0]) 97 | if pfpath in compiled_files: 98 | eL = self.cmap[pfpath] 99 | for e in eL: 100 | compile_commands.append( 101 | "{\"directory\":%s,\"command\":%s,\"file\":%s}"%( 102 | json.dumps(e.cwd.replace(source_root,nroot)), 103 | json.dumps(json_command(e.argv).replace(source_root,nroot)), 104 | json.dumps(pfpath.replace(source_root,nroot)) 105 | ) 106 | ) 107 | 108 | if not os.path.exists(outdir): 109 | os.makedirs(outdir) 110 | 111 | with open(os.path.join(outdir,"compile_commands.json"),"w") as f: 112 | f.write(json.dumps(json.loads("[%s]"%",".join(compile_commands)), indent=4, sort_keys=False)) 113 | print ("Written compilation database") 114 | 115 | # Write project files 116 | 117 | # Copy the project files 118 | sys.stdout.write("Copying project files... 0/%d"%(len(pflst)+len(lnklst))) 119 | sys.stdout.flush() 120 | cnt=0 121 | for pfn,pfroot in pflst: 122 | pfpath = os.path.join(pfroot,pfn) 123 | dst_path = os.path.join(nroot,pfn) 124 | if not os.path.exists(os.path.dirname(dst_path)): 125 | os.makedirs(os.path.dirname(dst_path)) 126 | shutil.copyfile(pfpath,dst_path) 127 | cnt+=1 128 | sys.stdout.write("\rCopying project files... %d/%d"%(cnt,len(pflst)+len(lnklst))) 129 | sys.stdout.write("\n") 130 | sys.stdout.flush() 131 | # Now handle the links 132 | for pfn,pfroot,lnk in lnklst: 133 | dst_path = os.path.join(nroot,pfn) 134 | if not os.path.exists(os.path.dirname(dst_path)): 135 | os.makedirs(os.path.dirname(dst_path)) 136 | if os.path.exists(dst_path): 137 | os.remove(dst_path) 138 | os.symlink(lnk, dst_path) 139 | cnt+=1 140 | sys.stdout.write("\rCopying project files... %d/%d"%(cnt,len(pflst)+len(lnklst))) 141 | print() -------------------------------------------------------------------------------- /bas/input_name.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * Parsing gcc command line in the search for the input file(s) passed to the compiler is not a trivial task in general 6 | * So here we have an extraordinarily complicated gcc plugin that can actually extract the name(s) for us from gcc internals 7 | */ 8 | 9 | /* All plugin sources should start including "gcc-plugin.h". */ 10 | #include "gcc-plugin.h" 11 | 12 | /* This let us inspect the GENERIC intermediate representation. */ 13 | #include "tree.h" 14 | 15 | /* All plugins must export this symbol so that they can be linked with GCC license-wise. */ 16 | int plugin_is_GPL_compatible; 17 | 18 | extern const char **in_fnames; 19 | extern unsigned num_in_fnames; 20 | 21 | void fn_start_unit_print_compiled_filename(void *gcc_data, void *user_data) { 22 | 23 | unsigned i; 24 | for (i=0; ibase_name; 37 | struct plugin_info pi = { "0.1", "Plugin to get names of files under compilation" }; 38 | register_callback (plugin_name, PLUGIN_START_UNIT, fn_start_unit_print_compiled_filename, &pi); 39 | 40 | /* Check everything is fine displaying a familiar message. */ 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /bas/maps.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAPS_H__ 2 | #define __MAPS_H__ 3 | 4 | #include 5 | #include "rbtree.h" 6 | 7 | struct nfsdb_entryMap_node { 8 | struct rb_node node; 9 | unsigned long key; 10 | struct nfsdb_entry** entry_list; 11 | unsigned long entry_count; 12 | unsigned long custom_data; 13 | }; 14 | 15 | struct ulongMap_node { 16 | struct rb_node node; 17 | unsigned long key; 18 | unsigned long* value_list; 19 | unsigned long value_count; 20 | unsigned long value_alloc; 21 | }; 22 | 23 | struct ulongPairMap_node { 24 | struct rb_node node; 25 | unsigned long key0; 26 | unsigned long key1; 27 | unsigned long* value_list; 28 | unsigned long value_count; 29 | unsigned long value_alloc; 30 | }; 31 | 32 | struct stringRefMap_node { 33 | struct rb_node node; 34 | const char* key; 35 | unsigned long value; 36 | }; 37 | 38 | enum file_access_type { 39 | FILE_ACCESS_TYPE_OPEN, 40 | FILE_ACCESS_TYPE_EXEC, 41 | FILE_ACCESS_TYPE_OPENEXEC, 42 | }; 43 | 44 | struct nfsdb_fileMap_node { 45 | struct rb_node node; 46 | unsigned long key; 47 | struct nfsdb_entry** rd_entry_list; 48 | unsigned long* rd_entry_index; 49 | unsigned long rd_entry_count; 50 | struct nfsdb_entry** wr_entry_list; 51 | unsigned long* wr_entry_index; 52 | unsigned long wr_entry_count; 53 | struct nfsdb_entry** rw_entry_list; 54 | unsigned long* rw_entry_index; 55 | unsigned long rw_entry_count; 56 | struct nfsdb_entry** ga_entry_list; 57 | unsigned long* ga_entry_index; 58 | unsigned long ga_entry_count; 59 | unsigned long global_access; 60 | enum file_access_type access_type; 61 | }; 62 | 63 | struct nfsdb_entryMap_node* nfsdb_entryMap_search(const struct rb_root* nfsdb_entryMap, unsigned long key); 64 | int nfsdb_entryMap_insert(struct rb_root* nfsdb_entryMap, unsigned long key, struct nfsdb_entry** entry_list, 65 | unsigned long count); 66 | void nfsdb_entryMap_destroy(struct rb_root* nfsdb_entryMap); 67 | size_t nfsdb_entryMap_count(const struct rb_root* nfsdb_entryMap); 68 | size_t nfsdb_entryMap_entry_count(const struct rb_root* nfsdb_entryMap); 69 | struct ulongMap_node* ulongMap_search(const struct rb_root* ulongMap, unsigned long key); 70 | int ulongMap_insert(struct rb_root* ulongMap, unsigned long key, unsigned long* value, unsigned long count, unsigned long alloc_size); 71 | void ulongMap_destroy(struct rb_root* ulongMap); 72 | size_t ulongMap_count(const struct rb_root* ulongMap); 73 | size_t ulongMap_entry_count(const struct rb_root* ulongMap); 74 | struct ulongPairMap_node* ulongPairMap_search(const struct rb_root* ulongPairMap, unsigned long key0, unsigned long key1); 75 | int ulongPairMap_insert(struct rb_root* ulongPairMap, unsigned long key0, unsigned long key1, unsigned long* value, 76 | unsigned long count, unsigned long alloc); 77 | void ulongPairMap_destroy(struct rb_root* ulongPairMap); 78 | size_t ulongPairMap_count(const struct rb_root* ulongPairMap); 79 | size_t ulongPairMap_entry_count(const struct rb_root* ulongPairMap); 80 | struct stringRefMap_node* stringRefMap_search(const struct rb_root* stringMap, const char* key); 81 | struct stringRefMap_node* stringRefMap_insert(struct rb_root* stringMap, const char* key, unsigned long value); 82 | void stringRefMap_remove(struct rb_root* stringRefMap, struct stringRefMap_node* node); 83 | void stringRefMap_destroy(struct rb_root* stringMap); 84 | size_t stringRefMap_count(const struct rb_root* stringMap); 85 | struct nfsdb_fileMap_node* fileMap_search(const struct rb_root* fileMap, unsigned long key); 86 | struct nfsdb_fileMap_node* fileMap_insert_key(struct rb_root* fileMap, unsigned long key); 87 | void fileMap_destroy(struct rb_root* fileMap); 88 | size_t fileMap_count(const struct rb_root* fileMap); 89 | size_t fileMap_rd_entry_count(const struct rb_root* fileMap); 90 | size_t fileMap_wr_entry_count(const struct rb_root* fileMap); 91 | size_t fileMap_rw_entry_count(const struct rb_root* fileMap); 92 | 93 | struct ulong_entryMap_node { 94 | struct rb_node node; 95 | unsigned long key; 96 | void* entry; 97 | }; 98 | 99 | typedef struct ulong_entryMap_node ftdb_ulong_type_entryMap; 100 | typedef struct ulong_entryMap_node ftdb_ulong_func_entryMap; 101 | typedef struct ulong_entryMap_node ftdb_ulong_funcdecl_entryMap; 102 | typedef struct ulong_entryMap_node ftdb_ulong_global_entryMap; 103 | typedef struct ulong_entryMap_node ftdb_ulong_static_funcs_map_entryMap; 104 | 105 | struct stringRef_entryMap_node { 106 | struct rb_node node; 107 | const char* key; 108 | void* entry; 109 | }; 110 | 111 | typedef struct stringRef_entryMap_node ftdb_stringRef_type_entryMap; 112 | typedef struct stringRef_entryMap_node ftdb_stringRef_func_entryMap; 113 | typedef struct stringRef_entryMap_node ftdb_stringRef_funcdecl_entryMap; 114 | typedef struct stringRef_entryMap_node ftdb_stringRef_global_entryMap; 115 | typedef struct stringRef_entryMap_node ftdb_stringRef_BAS_data_entryMap; 116 | 117 | struct stringRef_entryListMap_node { 118 | struct rb_node node; 119 | const char* key; 120 | void** entry_list; 121 | unsigned long entry_count; 122 | }; 123 | 124 | typedef struct stringRef_entryListMap_node ftdb_stringRef_func_entryListMap; 125 | typedef struct stringRef_entryListMap_node ftdb_stringRef_global_entryListMap; 126 | 127 | struct ulong_entryMap_node* ulong_entryMap_search(const struct rb_root* ulong_entryMap, unsigned long key); 128 | int ulong_entryMap_insert(struct rb_root* ulong_entryMap, unsigned long key, void* entry); 129 | void ulong_entryMap_destroy(struct rb_root* ulong_entryMap); 130 | size_t ulong_entryMap_count(const struct rb_root* ulong_entryMap); 131 | 132 | struct stringRef_entryMap_node* stringRef_entryMap_search(const struct rb_root* stringRef_entryMap, const char* key); 133 | int stringRef_entryMap_insert(struct rb_root* stringRef_entryMap, const char* key, void* entry); 134 | void stringRef_entryMap_destroy(struct rb_root* stringRef_entryMap); 135 | size_t stringRef_entryMap_count(const struct rb_root* stringRef_entryMap); 136 | 137 | struct stringRef_entryListMap_node* stringRef_entryListMap_search(const struct rb_root* stringRef_entryListMap, const char* key); 138 | int stringRef_entryListMap_insert(struct rb_root* stringRef_entryListMap, const char* key, void** entry_list, unsigned long entry_count); 139 | void stringRef_entryListMap_destroy(struct rb_root* stringRef_entryListMap); 140 | size_t stringRef_entryListMap_count(const struct rb_root* stringRef_entryListMap); 141 | size_t stringRef_entryListMap_entry_count(const struct rb_root* stringRef_entryListMap); 142 | 143 | #endif /* __MAPS_H__ */ 144 | -------------------------------------------------------------------------------- /bas/nfsdb.h: -------------------------------------------------------------------------------- 1 | #ifndef __NFSDB_H__ 2 | #define __NFSDB_H__ 3 | 4 | #include "maps.h" 5 | 6 | /* 7 | * .nfsdb and .nfsdb.deps version tracking. Make sure to modify these values 8 | * after every change to libetrace that could affect backward compatibility. 9 | * 10 | * NFSDB_MAGIC_NUMBER - distinguish .nfsdb database from other .img files 11 | * NFSDB_DEPS_MAGIC_NUMBER - distinguish .deps database from other .img files 12 | * LIBETRACE_VERSION - required etrace version to support file 13 | */ 14 | #define NFSDB_MAGIC_NUMBER 0x424453464e42494cULL /* b'LIBNFSDB' */ 15 | #define NFSDB_DEPS_MAGIC_NUMBER 0x5350454442494cULL /* b'LIBDEPS\0' */ 16 | #define LIBETRACE_VERSION 4ULL 17 | 18 | 19 | struct eid { 20 | unsigned long pid; 21 | unsigned long exeidx; 22 | }; 23 | 24 | struct cid { 25 | unsigned long pid; 26 | unsigned long flags; 27 | }; 28 | 29 | struct openfile { 30 | unsigned long path; 31 | unsigned long mode; 32 | unsigned long size; 33 | unsigned long* original_path; 34 | unsigned long open_timestamp; 35 | unsigned long close_timestamp; 36 | const struct nfsdb_entry* opaque_entry; 37 | }; 38 | 39 | struct pp_def { 40 | unsigned long name; 41 | unsigned long value; 42 | }; 43 | 44 | struct nfsdb_entry_file_index { 45 | unsigned long nfsdb_index; 46 | unsigned long open_index; 47 | int __used; 48 | }; 49 | 50 | struct compilation_info { 51 | unsigned long* compiled_list; 52 | struct nfsdb_entry_file_index* compiled_index; 53 | unsigned long compiled_count; 54 | unsigned long* include_paths; 55 | unsigned long include_paths_count; 56 | struct pp_def* pp_defs; 57 | unsigned long pp_defs_count; 58 | struct pp_def* pp_udefs; 59 | unsigned long pp_udefs_count; 60 | unsigned long* header_list; 61 | struct nfsdb_entry_file_index* header_index; 62 | unsigned long header_list_count; 63 | int compilation_type; 64 | int integrated_compilation; 65 | unsigned long* object_list; 66 | struct nfsdb_entry_file_index* object_index; 67 | unsigned long object_list_count; 68 | }; 69 | 70 | struct nfsdb_entry { 71 | unsigned long nfsdb_index; 72 | struct eid eid; 73 | unsigned long stime; 74 | unsigned long etime; 75 | struct eid parent_eid; 76 | struct cid* child_ids; 77 | unsigned long child_ids_count; 78 | unsigned long binary; 79 | unsigned long cwd; 80 | unsigned long bpath; 81 | unsigned long* argv; 82 | unsigned long argv_count; 83 | struct openfile* open_files; 84 | unsigned long open_files_count; 85 | unsigned char* pcp; 86 | unsigned long pcp_count; 87 | unsigned long wrapper_pid; 88 | struct eid* pipe_eids; 89 | unsigned long pipe_eids_count; 90 | struct compilation_info* compilation_info; 91 | unsigned long* linked_file; 92 | struct nfsdb_entry_file_index linked_index; 93 | int linked_type; 94 | int has_shared_argv; 95 | int return_code; 96 | }; 97 | 98 | struct nfsdb_deps { 99 | /* nfsdb.deps.img header - DO NOT modify */ 100 | unsigned long long db_magic; 101 | unsigned long long db_version; 102 | /* End of FTDB.img header */ 103 | 104 | struct rb_root depmap; 105 | struct rb_root ddepmap; 106 | struct rb_root revdepmap; 107 | struct rb_root revddepmap; 108 | }; 109 | 110 | struct nfsdb { 111 | /* nfsdb.img header - DO NOT modify */ 112 | unsigned long long db_magic; 113 | unsigned long long db_version; 114 | /* End of FTDB.img header */ 115 | 116 | struct nfsdb_entry* nfsdb; 117 | unsigned long nfsdb_count; 118 | const char* source_root; 119 | unsigned long source_root_size; 120 | const char* dbversion; 121 | const char** string_table; 122 | uint32_t* string_size_table; 123 | unsigned long string_table_size; 124 | unsigned long string_count; 125 | const char** pcp_pattern_list; 126 | unsigned long pcp_pattern_list_size; 127 | unsigned long* shared_argv_list; 128 | unsigned long shared_argv_list_size; 129 | struct rb_root procmap; 130 | struct rb_root bmap; 131 | struct rb_root forkmap; 132 | struct rb_root revforkmap; 133 | struct rb_root pipemap; 134 | struct rb_root wrmap; 135 | struct rb_root revwrmap; 136 | struct rb_root rdmap; 137 | struct rb_root revstringmap; 138 | struct rb_root filemap; 139 | struct rb_root linkedmap; 140 | }; 141 | 142 | #endif /* __NFSDB_H__ */ 143 | -------------------------------------------------------------------------------- /bas/phash.h: -------------------------------------------------------------------------------- 1 | /* ANSI-C code produced by gperf version 3.1 */ 2 | /* Command-line: gperf phash.txt */ 3 | /* Computed positions: -k'1-2,9,$' */ 4 | 5 | #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ 6 | && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ 7 | && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ 8 | && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ 9 | && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ 10 | && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ 11 | && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ 12 | && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ 13 | && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ 14 | && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ 15 | && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ 16 | && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ 17 | && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ 18 | && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ 19 | && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ 20 | && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ 21 | && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ 22 | && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ 23 | && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ 24 | && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ 25 | && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ 26 | && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ 27 | && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) 28 | /* The character set is not based on ISO-646. */ 29 | #error "gperf generated tables don't work with this execution character set. Please report a bug to ." 30 | #endif 31 | 32 | 33 | #define TOTAL_KEYWORDS 98 34 | #define MIN_WORD_LENGTH 2 35 | #define MAX_WORD_LENGTH 16 36 | #define MIN_HASH_VALUE 2 37 | #define MAX_HASH_VALUE 212 38 | /* maximum key range = 211, duplicates = 0 */ 39 | 40 | #ifdef __GNUC__ 41 | __inline 42 | #else 43 | #ifdef __cplusplus 44 | inline 45 | #endif 46 | #endif 47 | static unsigned int 48 | hash (const char *str, size_t len) 49 | { 50 | static unsigned char asso_values[] = 51 | { 52 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 53 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 54 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 55 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 56 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 120, 57 | 100, 213, 213, 213, 213, 213, 213, 213, 213, 213, 58 | 213, 213, 213, 213, 213, 35, 213, 60, 60, 10, 59 | 20, 213, 213, 105, 213, 213, 20, 55, 75, 45, 60 | 0, 213, 10, 5, 0, 55, 213, 30, 25, 213, 61 | 213, 0, 213, 213, 213, 5, 213, 65, 213, 40, 62 | 0, 0, 15, 213, 213, 10, 213, 0, 35, 10, 63 | 25, 20, 40, 213, 10, 35, 5, 30, 213, 85, 64 | 5, 65, 213, 213, 213, 213, 213, 213, 213, 213, 65 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 66 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 67 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 68 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 69 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 70 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 71 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 72 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 73 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 74 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 75 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 76 | 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 77 | 213, 213, 213, 213, 213, 213 78 | }; 79 | unsigned int hval = len; 80 | 81 | switch (hval) 82 | { 83 | default: 84 | hval += asso_values[(unsigned char)str[8]]; 85 | /*FALLTHROUGH*/ 86 | case 8: 87 | case 7: 88 | case 6: 89 | case 5: 90 | case 4: 91 | case 3: 92 | case 2: 93 | hval += asso_values[(unsigned char)str[1]]; 94 | /*FALLTHROUGH*/ 95 | case 1: 96 | hval += asso_values[(unsigned char)str[0]]; 97 | break; 98 | } 99 | return hval + asso_values[(unsigned char)str[len - 1]]; 100 | } 101 | -------------------------------------------------------------------------------- /bas/phash.txt: -------------------------------------------------------------------------------- 1 | New_proc 2 | SchedFork 3 | SysClone 4 | Close 5 | Pipe 6 | Open 7 | RenameFrom 8 | Rename2From 9 | Mount 10 | Umount 11 | LinkFrom 12 | LinkatFrom 13 | Symlink 14 | RenameTo 15 | RenameFailed 16 | LinkTo 17 | LinkFailed 18 | Exit 19 | UPID 20 | Env[ 21 | pid 22 | time 23 | timen 24 | argsize 25 | ppid 26 | fd 27 | flags 28 | mode 29 | fnamesize 30 | forigsize 31 | sourcenamesize 32 | typenamesize 33 | targetnamesize 34 | linknamesize 35 | resolvednamesize 36 | Progname_i 37 | Progname_p 38 | End_of_args 39 | fd1 40 | fd2 41 | cpu 42 | cwd 43 | prognameisize 44 | prognamepsize 45 | cwdsize 46 | Cont 47 | Cont_end 48 | SysCloneFailed 49 | Dup 50 | oldfd 51 | newfd 52 | status 53 | A[ 54 | PI 55 | PP 56 | CW 57 | FN 58 | FO 59 | RF 60 | RT 61 | LF 62 | LT 63 | ST 64 | SR 65 | SL 66 | MS 67 | MT 68 | MX 69 | PI[ 70 | PP[ 71 | CW[ 72 | FN[ 73 | FO[ 74 | RF[ 75 | RT[ 76 | LF[ 77 | LT[ 78 | ST[ 79 | SR[ 80 | SL[ 81 | MS[ 82 | MT[ 83 | MX[ 84 | PI_end 85 | PP_end 86 | CW_end 87 | FN_end 88 | FO_end 89 | RF_end 90 | RT_end 91 | LF_end 92 | LT_end 93 | ST_end 94 | SR_end 95 | SL_end 96 | MS_end 97 | MT_end 98 | MX_end 99 | -------------------------------------------------------------------------------- /bas/strnstr.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2001 Mike Barcroft 3 | * Copyright (c) 1990, 1993 4 | * The Regents of the University of California. All rights reserved. 5 | * 6 | * This code is derived from software contributed to Berkeley by 7 | * Chris Torek. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 3. Neither the name of the University nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | */ 33 | 34 | #include 35 | 36 | /* 37 | * Find the first occurrence of find in s, where the search is limited to the 38 | * first slen characters of s. 39 | */ 40 | char * strnstr(const char *s, const char *find, size_t slen) { 41 | char c, sc; 42 | size_t len; 43 | 44 | if ((c = *find++) != '\0') { 45 | len = strlen(find); 46 | do { 47 | do { 48 | if (slen-- < 1 || (sc = *s++) == '\0') 49 | return (NULL); 50 | } while (sc != c); 51 | if (len > slen) 52 | return (NULL); 53 | } while (strncmp(s, find, len) != 0); 54 | s--; 55 | } 56 | return ((char *)s); 57 | } 58 | -------------------------------------------------------------------------------- /bas/tags.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /* Perfect hash values for selected strings */ 6 | enum class Tag { 7 | NewProc = 123, 8 | SchedFork = 54, 9 | SysClone = 78, 10 | SysCloneFailed = 104, 11 | Close = 100, 12 | Pipe = 14, 13 | Dup = 133, 14 | Open = 114, 15 | RenameFrom = 50, 16 | RenameTo = 38, 17 | Rename2From = 41, 18 | RenameFailed = 32, 19 | LinkFailed = 40, 20 | LinkTo = 56, 21 | LinkatFrom = 70, 22 | LinkFrom = 48, 23 | Symlink = 77, 24 | Exit = 24, 25 | Mount = 85, 26 | Umount = 76, 27 | 28 | UPID = 119, // UPID 29 | ProgramInterpreter = 212, // PI 30 | ProgramPath = 2, // PP 31 | CurrentWorkingDirectory = 122, // CW 32 | AbsolutePath = 172, // FN 33 | OriginalPath = 112, // FO 34 | RenameFromPath = 52, // RF 35 | RenameToPath = 12, // RT 36 | LinkFromPath = 62, // LF 37 | LinkToPath = 22, // LT 38 | SymlinkTargetName = 7, // ST 39 | SymlinkTargetPath = 27, // SR 40 | SymlinkPath = 47, // SL 41 | MountSource = 67, // MS 42 | MountTarget = 57, // MT 43 | MountType = 107, // MX 44 | 45 | ArrayedEnvs = 39, // Env[ 46 | ArrayedArguments = 37, // A[ 47 | ProgramInterpreterExtended = 108, // PI[ 48 | ProgramPathExtended = 3, // PP[ 49 | CurrentWorkingDirectoryExtended = 93, // CW[ 50 | AbsolutePathExtended = 98, // FN[ 51 | OriginalPathExtended = 68, // FO[ 52 | RenameFromPathExtended = 33, // RF[ 53 | RenameToPathExtended = 13, // RT[ 54 | LinkFromPathExtended = 43, // LF[ 55 | LinkToPathExtended = 23, // LT[ 56 | SymlinkTargetNameExtended = 8, // ST[ 57 | SymlinkTargetPathExtended = 18, // SR[ 58 | SymlinkPathExtended = 28, // SL[ 59 | MountSourceExtended = 63, // MS[ 60 | MountTargetExtended = 58, // MT[ 61 | MountTypeExtended = 83, // MX[ 62 | 63 | ProgramInterpreterEnd = 111, // PI_end 64 | ProgramPathEnd = 6, // PP_end 65 | CurrentWorkingDirectoryEnd = 96, // CW_end 66 | AbsolutePathEnd = 101, // FN_end 67 | OriginalPathEnd = 71, // FO_end 68 | RenameFromPathEnd = 36, // RF_end 69 | RenameToPathEnd = 16, // RT_end 70 | LinkFromPathEnd = 46, // LF_end 71 | LinkToPathEnd = 26, // LT_end 72 | SymlinkTargetNameEnd = 11, // ST_end 73 | SymlinkTargetPathEnd = 21, // SR_end 74 | SymlinkPathEnd = 31, // SL_end 75 | MountSourceEnd = 66, // MS_end 76 | MountTargetEnd = 61, // MT_end 77 | MountTypeEnd = 86, // MX_end 78 | 79 | EndOfArgs = 91, 80 | Cont = 89, 81 | ContEnd = 88, 82 | None = -1, 83 | }; 84 | 85 | enum class ShortArguments { 86 | Pid = 53, 87 | ArgSize = 82, 88 | Prognameisize = 73, 89 | Prognamepsize = 103, 90 | CwdSize = 132, 91 | Fd = 17, 92 | Fd1 = 138, 93 | Fd2 = 118, 94 | Oldfd = 60, 95 | Newfd = 30, 96 | Flags = 90, 97 | Mode = 34, 98 | Fnamesize = 49, 99 | Forigsize = 44, 100 | Sourcenamesize = 79, 101 | Typenamesize = 117, 102 | Targetnamesize = 94, 103 | Linknamesize = 92, 104 | Resolvednamesize = 51, 105 | Status = 81, 106 | }; 107 | 108 | 109 | // std::ostream& operator<<(std::ostream &o, const Tag &tag); 110 | -------------------------------------------------------------------------------- /cas: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import os 5 | 6 | if __name__ == '__main__': 7 | if len(sys.argv) > 1 and sys.argv[1] == "bash_complete": 8 | from client.argparser import get_bash_complete 9 | print(get_bash_complete()) 10 | exit(0) 11 | 12 | cas_dir = os.path.dirname(os.path.realpath(__file__)) 13 | # this should bypas problems with execve of etrace_parser 14 | if cas_dir not in os.environ["PATH"]: 15 | os.environ["PATH"] = os.environ["PATH"] + f":{cas_dir}" 16 | 17 | try: 18 | import libetrace as _ 19 | except ModuleNotFoundError: 20 | print("CAS libetrace not found - provide libetrace.so in directory or export directory with library to PYTHONPATH") 21 | print("eg. export PYTHONPATH=/home/j.doe/CAS/:$PYTHONPATH") 22 | sys.exit(2) 23 | 24 | from signal import signal, SIGPIPE, SIG_DFL 25 | 26 | signal(SIGPIPE, SIG_DFL) 27 | 28 | args = sys.argv[1:] 29 | 30 | if "--proc-tree" in args or "--deps-tree" in args: 31 | import webbrowser 32 | import threading 33 | try: 34 | browser = webbrowser.get() 35 | except webbrowser.Error: 36 | print ("NO BROWSER") 37 | 38 | from cas_server import app, translate_to_url 39 | 40 | port = 8383 41 | try: 42 | port_idx = list(map(lambda x: x.startswith("--port"), args)).index(True) 43 | port = int(args[port_idx].split('=')[1]) 44 | args.pop(port_idx) 45 | except Exception: 46 | pass 47 | 48 | host = "0.0.0.0" 49 | try: 50 | host_idx = list(map(lambda x: x.startswith("--host"), args)).index(True) 51 | host = args[host_idx].split('=')[1] 52 | args.pop(host_idx) 53 | except Exception: 54 | pass 55 | 56 | url_args = translate_to_url(args) 57 | def browser_spawn(): 58 | browser.open(f"http://{host}:{port}/{url_args}", new=2) 59 | 60 | threading.Thread(target=browser_spawn).start() 61 | app.run(host, port) 62 | else: 63 | import os 64 | from typing import Generator, Iterator 65 | import libcas 66 | from libft_db import FTDatabase 67 | from client.cmdline import process_commandline 68 | from client.exceptions import MessageException 69 | 70 | cas_db = libcas.CASDatabase() 71 | ft_db = FTDatabase() 72 | try: 73 | ret = process_commandline(cas_db, ft_db=ft_db) 74 | if ret: 75 | if isinstance(ret, Iterator): 76 | print(*ret, sep=os.linesep) 77 | elif isinstance(ret, Generator): 78 | print(*ret, sep=os.linesep) 79 | else: 80 | print(ret, flush=True) 81 | except MessageException as e : 82 | print("ERROR: " + e.message) 83 | sys.exit(2) 84 | -------------------------------------------------------------------------------- /clang-proc/LICENSE: -------------------------------------------------------------------------------- 1 | Function/Type database (FTDB) processor, part of the Code Aware Services (CAS) suite 2 | Copyright [2022] [Samsung Electronics Co., Ltd.] 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Some files in this project was taken (and modified) from the original clang source code. 17 | These files are: 18 | - */DeclPrinter.cpp 19 | - */StmtPrinter.cpp 20 | - */TypePrinter.cpp 21 | Please note the notices for the changes. 22 | 23 | Base 64 encoding/decoding utilities for C++ were taken from the library written by: 24 | Copyright (C) 2004-2017 René Nyffenegger 25 | Please see base64.cpp and base64.h files for details. 26 | 27 | Json parsing implementation (before modification) was taken from the SimpleJSON 28 | library (https://github.com/nbsdx/SimpleJSON.git) and therefore might be distributed 29 | under the WTFPL license (please see json.hpp file). 30 | 31 | SHA computing functions were taken from the legacy Android bootloader contributed 32 | to the Android Open Source Project. Please see sha.cpp and sha.h files for details. 33 | -------------------------------------------------------------------------------- /clang-proc/MacroHandler.h: -------------------------------------------------------------------------------- 1 | #include "clang/Lex/Preprocessor.h" 2 | #include "clang/Lex/PPCallbacks.h" 3 | #include "compat.h" 4 | 5 | #include 6 | using namespace clang; 7 | using RangeMap = std::map; 8 | using MacroExpMap = std::map; 9 | using SkippedMap = std::map>>; 10 | 11 | // helper class registering preprocessor callbacks and collecting data 12 | class MacroHandler{ 13 | public: 14 | MacroHandler(Preprocessor &PP, bool save_expansions); 15 | const char *getExpansionText(SourceLocation MacroExpLoc) const; 16 | auto& getExpansionRanges(){return ExpansionRanges;} 17 | auto& getSkippedRanges(){return SkippedRanges;} 18 | 19 | private: 20 | Preprocessor &PP; 21 | MacroExpMap MacroExpansions; 22 | RangeMap ExpansionRanges; 23 | SkippedMap SkippedRanges; 24 | void onTokenLexed(const Token &Tok); 25 | }; -------------------------------------------------------------------------------- /clang-proc/base64.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | base64.cpp and base64.h 3 | 4 | base64 encoding and decoding with C++. 5 | 6 | Version: 1.01.00 7 | 8 | Copyright (C) 2004-2017 René Nyffenegger 9 | 10 | This source code is provided 'as-is', without any express or implied 11 | warranty. In no event will the author be held liable for any damages 12 | arising from the use of this software. 13 | 14 | Permission is granted to anyone to use this software for any purpose, 15 | including commercial applications, and to alter it and redistribute it 16 | freely, subject to the following restrictions: 17 | 18 | 1. The origin of this source code must not be misrepresented; you must not 19 | claim that you wrote the original source code. If you use this source code 20 | in a product, an acknowledgment in the product documentation would be 21 | appreciated but is not required. 22 | 23 | 2. Altered source versions must be plainly marked as such, and must not be 24 | misrepresented as being the original source code. 25 | 26 | 3. This notice may not be removed or altered from any source distribution. 27 | 28 | René Nyffenegger rene.nyffenegger@adp-gmbh.ch 29 | 30 | */ 31 | 32 | #include "base64.h" 33 | #include 34 | 35 | static const std::string base64_chars = 36 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 37 | "abcdefghijklmnopqrstuvwxyz" 38 | "0123456789+/"; 39 | 40 | 41 | static inline bool is_base64(unsigned char c) { 42 | return (isalnum(c) || (c == '+') || (c == '/')); 43 | } 44 | 45 | std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { 46 | std::string ret; 47 | int i = 0; 48 | int j = 0; 49 | unsigned char char_array_3[3]; 50 | unsigned char char_array_4[4]; 51 | 52 | while (in_len--) { 53 | char_array_3[i++] = *(bytes_to_encode++); 54 | if (i == 3) { 55 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 56 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 57 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 58 | char_array_4[3] = char_array_3[2] & 0x3f; 59 | 60 | for(i = 0; (i <4) ; i++) 61 | ret += base64_chars[char_array_4[i]]; 62 | i = 0; 63 | } 64 | } 65 | 66 | if (i) 67 | { 68 | for(j = i; j < 3; j++) 69 | char_array_3[j] = '\0'; 70 | 71 | char_array_4[0] = ( char_array_3[0] & 0xfc) >> 2; 72 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 73 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 74 | 75 | for (j = 0; (j < i + 1); j++) 76 | ret += base64_chars[char_array_4[j]]; 77 | 78 | while((i++ < 3)) 79 | ret += '='; 80 | 81 | } 82 | 83 | return ret; 84 | 85 | } 86 | 87 | std::string base64_decode(std::string const& encoded_string) { 88 | int in_len = encoded_string.size(); 89 | int i = 0; 90 | int j = 0; 91 | int in_ = 0; 92 | unsigned char char_array_4[4], char_array_3[3]; 93 | std::string ret; 94 | 95 | while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { 96 | char_array_4[i++] = encoded_string[in_]; in_++; 97 | if (i ==4) { 98 | for (i = 0; i <4; i++) 99 | char_array_4[i] = base64_chars.find(char_array_4[i]); 100 | 101 | char_array_3[0] = ( char_array_4[0] << 2 ) + ((char_array_4[1] & 0x30) >> 4); 102 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 103 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 104 | 105 | for (i = 0; (i < 3); i++) 106 | ret += char_array_3[i]; 107 | i = 0; 108 | } 109 | } 110 | 111 | if (i) { 112 | for (j = 0; j < i; j++) 113 | char_array_4[j] = base64_chars.find(char_array_4[j]); 114 | 115 | char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); 116 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 117 | 118 | for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; 119 | } 120 | 121 | return ret; 122 | } 123 | -------------------------------------------------------------------------------- /clang-proc/base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // base64 encoding and decoding with C++. 3 | // Version: 1.01.00 4 | // 5 | 6 | #ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A 7 | #define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A 8 | 9 | #include 10 | 11 | std::string base64_encode(unsigned char const* , unsigned int len); 12 | std::string base64_decode(std::string const& s); 13 | 14 | #endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */ 15 | -------------------------------------------------------------------------------- /clang-proc/compat.h: -------------------------------------------------------------------------------- 1 | #ifndef FTDB_COMPAT_H 2 | #define FTDB_COMPAT_H 3 | #include "clang/AST/Expr.h" 4 | #include "clang/Basic/SourceManager.h" 5 | #include "clang/AST/DeclTemplate.h" 6 | 7 | #if CLANG_VERSION==11 8 | #include "clang/Basic/FileManager.h" 9 | #elif CLANG_VERSION>=12 10 | #include "clang/Basic/FileEntry.h" 11 | #endif 12 | 13 | #if CLANG_VERSION>=10 14 | #define COMPAT_VERSION_GE_10(code) code 15 | #else 16 | #define COMPAT_VERSION_GE_10(code) 17 | #endif 18 | 19 | #if CLANG_VERSION>=15 20 | #define COMPAT_VERSION_GE_15(code) code 21 | #else 22 | #define COMPAT_VERSION_GE_15(code) 23 | #endif 24 | 25 | #define COMPAT_VERSION_GE(v,code) COMPAT_VERSION_GE_##v(code) 26 | 27 | #if CLANG_VERSION<11 28 | #define FTDB_COMPAT_MACRO_OFFSET -2 29 | #else 30 | #define FTDB_COMPAT_MACRO_OFFSET 0 31 | #endif 32 | 33 | #if CLANG_VERSION<16 34 | #define getUnmodifiedType getUnderlyingType 35 | #endif 36 | 37 | #if CLANG_VERSION>=16 38 | #define compatGetValue value 39 | #else 40 | #define compatGetValue getValue 41 | #endif 42 | 43 | using namespace clang; 44 | 45 | namespace compatibility{ 46 | inline void EvaluateAsConstantExpr(const Expr *E,Expr::EvalResult &Res,ASTContext &Context){ 47 | #if CLANG_VERSION>=12 48 | E->EvaluateAsConstantExpr(Res, Context); 49 | #else 50 | E->EvaluateAsConstantExpr(Res, Expr::EvaluateForCodeGen, Context); 51 | #endif 52 | } 53 | 54 | inline std::string toString(llvm::APSInt Iv){ 55 | #if CLANG_VERSION>=13 56 | llvm::SmallVector tmp; 57 | Iv.toString(tmp,10); 58 | return std::string(tmp.begin(),tmp.end()); 59 | #else 60 | return Iv.toString(10); 61 | #endif 62 | } 63 | 64 | inline CompoundStmt *createEmptyCompoundStmt(ASTContext &Ctx){ 65 | #if CLANG_VERSION>=15 66 | return CompoundStmt::CreateEmpty(Ctx,1,0); 67 | #else 68 | return CompoundStmt::CreateEmpty(Ctx,1); 69 | #endif 70 | } 71 | 72 | inline const TemplateTypeParmType *getReplacedParmType(const SubstTemplateTypeParmType* tp){ 73 | #if CLANG_VERSION>=16 74 | return cast(tp->getReplacedParameter()->getTypeForDecl()); 75 | #else 76 | return tp->getReplacedParameter(); 77 | #endif 78 | } 79 | } 80 | #endif //FTDB_COMPAT_H -------------------------------------------------------------------------------- /clang-proc/create_json_db: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import argparse 6 | import jsonast 7 | 8 | prog = os.path.realpath(__file__) 9 | 10 | if __name__ == "__main__": 11 | 12 | parser = argparse.ArgumentParser(description="MAIN_DESCRIPTION", formatter_class=argparse.RawDescriptionHelpFormatter) 13 | 14 | # execution control 15 | parser.add_argument("-P", "--proc-binary", action="store", help="Path to the processor binary based on clang") 16 | parser.add_argument("-j", "--jobs", action="store", type=int, help="Run only with specific number of jobs", required=False) 17 | parser.add_argument("-Q", "--unique-cdb", action="store_true", help="Make compilation database unique while processing",required=False) 18 | 19 | 20 | # output control 21 | parser.add_argument("-img", "--image", action="store_true", help="generate .img file for database") 22 | parser.add_argument("-q", "--quiet", action="store_true", help="don't print any information on stdout") 23 | parser.add_argument("-d", "--debug", action="store_true", help="print debug information") 24 | parser.add_argument("-v", "--verbose", action="store_true", help="print verbose errors") 25 | parser.add_argument("-o", "--output", action="store", help="Output file") 26 | parser.add_argument("-O", "--forward-output", required=False, action="store", help="Store program output to the provided file") 27 | parser.add_argument("-S", "--clean-slate", action="store_true", help="Remove error (and debug) file(s) and store potential errors (debugs) from scratch",required=False) 28 | 29 | # target info 30 | parser.add_argument("-V", "--sw-version", required=False, action="store", help="Put information about S/W version to JSON database") 31 | parser.add_argument("-m", "--module-info", required=False, action="store", help="Put information about module being processed to JSON database") 32 | parser.add_argument("-C", "--compilation-database", action="store", help="Path to compilation database file (default compile_commands.json file in the current directory", required=False) 33 | parser.add_argument("-cdm", "--compilation-dependency-map", required=False, action="store", help="Path to compile dependency map file that contains mapping between modules and corresponding source files") 34 | 35 | # clang-proc options 36 | parser.add_argument("-B", "--skip-body", action="store_true", help="skip adding function body to the JSON database") 37 | parser.add_argument("-W", "--skip-switches", action="store_true", help="skip adding switch/case information the JSON database") 38 | parser.add_argument("-X", "--skip-defs", action="store_true", help="skip adding type definitions for certain types") 39 | parser.add_argument("-A", "--with-cta", action="store_true", help="merge compile time asserts into one declaration") 40 | parser.add_argument("-T", "--taint", action="store", help="add taint information for the function parameters to the JSON database (default: dbtaint.json file in script directory)") 41 | parser.add_argument("-fu", "--field-usage", required=False, action="store_true", help="Enable field usage information in JSON database (default: True)") 42 | parser.add_argument("-i", "--include-path", action="store_true", help="Add clang builtin include path to underlying clang processor",required=False) 43 | parser.add_argument("-L", "--additional-include-paths", action="append", help="Add additional include paths to underlying clang processor",required=False) 44 | parser.add_argument("-E", "--processor-error", action="store_true", help="pass '-E' option to the underlying processor",required=False) 45 | parser.add_argument("-DD", "--additional-defines", required=False, action="store", help="Path to JSON file that contains a list of additional preprocessor definitions to pass to all source files") 46 | parser.add_argument("-mr", "--macro-replacement", required=False, action="store", help="Path to JSON file that describes macro replacement to be done on sources") 47 | parser.add_argument("-me", "--macro-expansion", required=False, action="store_true", help="Enable tracking macro expansions for functions") 48 | parser.add_argument("-sa", "--enable-static-assert", required=False, action="store_true", help="Enable printing of static_assert in definitions' code") 49 | 50 | # for debugging 51 | parser.add_argument("-r", "--range", action="store", help="Range of input files to process (e.g. \"0:60\")") 52 | parser.add_argument("-c", "--compilation-list", action="store", help="List of compiled files to process (by default all unique compiled files from compilation database are processed)", required=False) 53 | parser.add_argument("-e", "--exit-on-error", action="store_true", help="Stop and exit on first error encountered",required=False) 54 | 55 | args = parser.parse_args() 56 | sys.exit(jsonast.create_json_db_main(args)) 57 | -------------------------------------------------------------------------------- /clang-proc/dbtaint.json: -------------------------------------------------------------------------------- 1 | { 2 | "exact_name": 3 | { 4 | "memcpy": 5 | [ 6 | [1, 2], 7 | [1, 3], 8 | [2, 3] 9 | ], 10 | "sscanf": 11 | [ 12 | [0, 1] 13 | ], 14 | "strcpy": 15 | [ 16 | [1, 2] 17 | ], 18 | "kstrndup": 19 | [ 20 | [1, 2] 21 | ], 22 | "kmemdup": 23 | [ 24 | [1, 2] 25 | ], 26 | "kmemdup_nul": 27 | [ 28 | [1, 2] 29 | ], 30 | "memdup_user": 31 | [ 32 | [1, 2] 33 | ], 34 | "strndup_user": 35 | [ 36 | [1, 2] 37 | ], 38 | "memdup_user_nul": 39 | [ 40 | [1, 2] 41 | ], 42 | "sprintf": 43 | [ 44 | [0, 1] 45 | ], 46 | "strncpy": 47 | [ 48 | [1, 2], 49 | [1, 3], 50 | [2, 3] 51 | ], 52 | "strlcpy": 53 | [ 54 | [1, 2], 55 | [1, 3], 56 | [2, 3] 57 | ], 58 | "strstr": 59 | [ 60 | [1, 2] 61 | ], 62 | "strsep": 63 | [ 64 | [1, 2] 65 | ], 66 | "strpbrk": 67 | [ 68 | [1, 2] 69 | ], 70 | "strspn": 71 | [ 72 | [1, 2] 73 | ], 74 | "strchr": 75 | [ 76 | [1, 2] 77 | ], 78 | "strrchr": 79 | [ 80 | [1, 2] 81 | ], 82 | "memchr": 83 | [ 84 | [1, 2], 85 | [1, 3] 86 | ], 87 | "copy_from_user": 88 | [ 89 | [1, 2], 90 | [1, 3], 91 | [2, 3] 92 | ], 93 | "copy_to_user": 94 | [ 95 | [1, 2], 96 | [1, 3], 97 | [2, 3] 98 | ], 99 | "simple_write_to_buffer": 100 | [ 101 | [1, 4], 102 | [1, 5], 103 | [4, 5] 104 | ], 105 | "simple_read_from_buffer": 106 | [ 107 | [1, 4], 108 | [1, 2], 109 | [4, 2] 110 | ] 111 | }, 112 | "regex_name": 113 | { 114 | "kstrto": 115 | [ 116 | [3,1] 117 | ], 118 | "simple_strto": 119 | [ 120 | [2,1] 121 | ] 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /clang-proc/main.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace json { 6 | class JSON; 7 | } 8 | 9 | extern int DEBUG_NOTICE; 10 | 11 | struct main_opts { 12 | bool call; 13 | bool assert; 14 | bool debug; 15 | bool debug2; 16 | bool debug3; 17 | bool debugNotice; 18 | bool debugDeref; 19 | bool debugbuild; 20 | bool debugME; 21 | bool brk; 22 | bool include; 23 | bool addbody; 24 | bool adddefs; 25 | bool switchopt; 26 | bool cstmt; 27 | bool taint; 28 | bool tudump; 29 | bool tudumpcont; 30 | bool tudumpwithsrc; 31 | bool onlysrc; 32 | bool recordLoc; 33 | bool exit_on_error; 34 | bool csd; 35 | bool ptrMEonly; 36 | bool save_expansions; 37 | }; 38 | 39 | extern main_opts opts; 40 | -------------------------------------------------------------------------------- /clang-proc/printers.h: -------------------------------------------------------------------------------- 1 | #include "clang/AST/Decl.h" 2 | #include 3 | 4 | extern thread_local int csd; 5 | extern bool enable_sa; 6 | extern thread_local std::set *CTAList; 7 | 8 | void setCTAList(std::set *List); 9 | 10 | void printRecordHead(clang::RecordDecl *D, llvm::raw_ostream &Out, const clang::PrintingPolicy &Policy); 11 | void printUnnamedTag(clang::TagDecl *D,llvm::raw_ostream &Out, const clang::PrintingPolicy &Policy); 12 | 13 | void setCustomStructDefs(bool _csd); 14 | void processDeclGroupNoClear(llvm::SmallVectorImpl& Decls, llvm::raw_ostream &Out, 15 | const clang::PrintingPolicy &Policy); -------------------------------------------------------------------------------- /clang-proc/sha.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2008 The Android Open Source Project 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Copyright 2008 Google Inc. All Rights Reserved. 18 | // Author: mschilder@google.com (Marius Schilder) 19 | // 20 | // Optimized for minimal code size. 21 | 22 | #include "sha.h" 23 | 24 | #define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits)))) 25 | 26 | static void SHA1_Transform(SHA_CTX* ctx) { 27 | uint32_t W[80]; 28 | uint32_t A, B, C, D, E; 29 | uint8_t* p = ctx->buf.b; 30 | int t; 31 | 32 | for(t = 0; t < 16; ++t) { 33 | uint32_t tmp = *p++ << 24; 34 | tmp |= *p++ << 16; 35 | tmp |= *p++ << 8; 36 | tmp |= *p++; 37 | W[t] = tmp; 38 | } 39 | 40 | for(; t < 80; t++) { 41 | W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 42 | } 43 | 44 | A = ctx->state[0]; 45 | B = ctx->state[1]; 46 | C = ctx->state[2]; 47 | D = ctx->state[3]; 48 | E = ctx->state[4]; 49 | 50 | for(t = 0; t < 80; t++) { 51 | uint32_t tmp = rol(5,A) + E + W[t]; 52 | 53 | if (t < 20) 54 | tmp += (D^(B&(C^D))) + 0x5A827999; 55 | else if ( t < 40) 56 | tmp += (B^C^D) + 0x6ED9EBA1; 57 | else if ( t < 60) 58 | tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC; 59 | else 60 | tmp += (B^C^D) + 0xCA62C1D6; 61 | 62 | E = D; 63 | D = C; 64 | C = rol(30,B); 65 | B = A; 66 | A = tmp; 67 | } 68 | 69 | ctx->state[0] += A; 70 | ctx->state[1] += B; 71 | ctx->state[2] += C; 72 | ctx->state[3] += D; 73 | ctx->state[4] += E; 74 | } 75 | 76 | void SHA_init(SHA_CTX* ctx) { 77 | ctx->state[0] = 0x67452301; 78 | ctx->state[1] = 0xEFCDAB89; 79 | ctx->state[2] = 0x98BADCFE; 80 | ctx->state[3] = 0x10325476; 81 | ctx->state[4] = 0xC3D2E1F0; 82 | ctx->count = 0; 83 | } 84 | 85 | 86 | void SHA_update(SHA_CTX* ctx, const void* data, int len) { 87 | int i = ctx->count % sizeof(ctx->buf); 88 | const uint8_t* p = (const uint8_t*)data; 89 | 90 | ctx->count += len; 91 | 92 | while (len--) { 93 | ctx->buf.b[i++] = *p++; 94 | if (i == sizeof(ctx->buf)) { 95 | SHA1_Transform(ctx); 96 | i = 0; 97 | } 98 | } 99 | } 100 | 101 | 102 | const uint8_t* SHA_final(SHA_CTX* ctx) { 103 | uint8_t *p = ctx->buf.b; 104 | uint64_t cnt = ctx->count * 8; 105 | int i; 106 | 107 | SHA_update(ctx, (uint8_t*)"\x80", 1); 108 | while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) { 109 | SHA_update(ctx, (uint8_t*)"\0", 1); 110 | } 111 | for (i = 0; i < 8; ++i) { 112 | uint8_t tmp = cnt >> ((7 - i) * 8); 113 | SHA_update(ctx, &tmp, 1); 114 | } 115 | 116 | for (i = 0; i < 5; i++) { 117 | uint32_t tmp = ctx->state[i]; 118 | *p++ = tmp >> 24; 119 | *p++ = tmp >> 16; 120 | *p++ = tmp >> 8; 121 | *p++ = tmp >> 0; 122 | } 123 | 124 | return ctx->buf.b; 125 | } 126 | 127 | /* Convenience function */ 128 | const uint8_t* SHA(const void* data, int len, uint8_t* digest) { 129 | const uint8_t* p; 130 | int i; 131 | SHA_CTX ctx; 132 | SHA_init(&ctx); 133 | SHA_update(&ctx, data, len); 134 | p = SHA_final(&ctx); 135 | for (i = 0; i < SHA_DIGEST_SIZE; ++i) { 136 | digest[i] = *p++; 137 | } 138 | return digest; 139 | } 140 | -------------------------------------------------------------------------------- /clang-proc/sha.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2008 The Android Open Source Project 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Copyright 2008 Google Inc. All Rights Reserved. 18 | // Author: mschilder@google.com (Marius Schilder) 19 | 20 | #ifndef _EMBEDDED_SHA_H_ 21 | #define _EMBEDDED_SHA_H_ 22 | 23 | #include 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif // __cplusplus 28 | 29 | typedef struct SHA_CTX { 30 | uint64_t count; 31 | uint32_t state[5]; 32 | union { 33 | uint8_t b[64]; 34 | uint32_t w[16]; 35 | } buf; 36 | } SHA_CTX; 37 | 38 | void SHA_init(SHA_CTX* ctx); 39 | void SHA_update(SHA_CTX* ctx, const void* data, int len); 40 | const uint8_t* SHA_final(SHA_CTX* ctx); 41 | 42 | // Convenience method. Returns digest parameter value. 43 | const uint8_t* SHA(const void* data, int len, uint8_t* digest); 44 | 45 | #define SHA_DIGEST_SIZE 20 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif // __cplusplus 50 | 51 | #endif // _EMBEDDED_SHA_H_ 52 | -------------------------------------------------------------------------------- /clang-proc/utils.cc: -------------------------------------------------------------------------------- 1 | #pragma GCC diagnostic ignored "-Wstrict-aliasing" 2 | #pragma GCC diagnostic ignored "-Wunused-variable" 3 | #pragma GCC diagnostic ignored "-Wpessimizing-move" 4 | 5 | #include "utils.h" 6 | 7 | namespace utils 8 | { 9 | 10 | std::vector getSyntaxOnlyToolArgs(const std::vector &extraArgs, llvm::StringRef fileName) 11 | { 12 | std::vector args; 13 | 14 | args.push_back("clang-tool"); 15 | args.push_back("-fsyntax-only"); 16 | 17 | args.insert(args.end(), extraArgs.begin(), extraArgs.end()); 18 | args.push_back(fileName.str()); 19 | 20 | return args; 21 | } 22 | 23 | bool fileExists(const std::string &file) 24 | { 25 | return std::ifstream(file).good(); 26 | } 27 | 28 | std::vector getCompileArgs(const std::vector &compileCommands) 29 | { 30 | std::vector compileArgs; 31 | 32 | for(auto &cmd : compileCommands) 33 | { 34 | for(auto &arg : cmd.CommandLine) 35 | compileArgs.push_back(arg); 36 | } 37 | 38 | if(compileArgs.empty() == false) 39 | { 40 | compileArgs.erase(begin(compileArgs)); 41 | compileArgs.pop_back(); 42 | } 43 | 44 | return compileArgs; 45 | } 46 | 47 | std::string getSourceCode(const std::string &sourceFile) 48 | { 49 | std::string sourcetxt = ""; 50 | std::string temp = ""; 51 | 52 | std::ifstream file(sourceFile); 53 | 54 | while(std::getline(file, temp)) 55 | sourcetxt += temp + "\n"; 56 | 57 | return sourcetxt; 58 | } 59 | 60 | std::string getClangBuiltInIncludePath(const std::string &fullCallPath) 61 | { 62 | return std::string(CLANG_BUILTIN_INCLUDE_PATH); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /clang-proc/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_HPP 2 | #define UTILS_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace utils 16 | { 17 | std::vector getSyntaxOnlyToolArgs(const std::vector &ExtraArgs, llvm::StringRef FileName); 18 | 19 | bool fileExists(const std::string &file); 20 | std::vector getCompileArgs(const std::vector &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 | 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 | 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 | --------------------------------------------------------------------------------