If unsure, say N.
-config SWAP_DA
- tristate "System Wide Analysis of Performance"
- depends on ARM || X86
- select KALLSYMS
- select DEBUG_FS
- help
- SWAP is a profiling tool.
-
- If unsure, say Y.
-
config OPROFILE_EVENT_MULTIPLEX
bool "OProfile multiplexing support (EXPERIMENTAL)"
default n
# CONFIG_AUDIT_TREE=y
# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set
CONFIG_HAVE_GENERIC_HARDIRQS=y
-CONFIG_SWAP_DA=y
#
# IRQ subsystem
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
-obj-$(CONFIG_SWAP_DA) += swap/
-
$(obj)/configs.o: $(obj)/config_data.h
# config_data.h contains the same information as ikconfig.h but gzipped.
+++ /dev/null
-# Doxyfile 1.8.7
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME = "SWAP Modules"
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER =
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF =
-
-# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
-# the documentation. The maximum height of the logo should not exceed 55 pixels
-# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
-# to the output directory.
-
-PROJECT_LOGO =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
-OUTPUT_DIRECTORY =
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS = NO
-
-# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
-# characters to appear in the names of generated files. If set to NO, non-ASCII
-# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
-# U+3044.
-# The default value is: NO.
-
-ALLOW_UNICODE_NAMES = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
-# description of a member or function before the detailed description
-#
-# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB = NO
-
-# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES = YES
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF = NO
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: YES.
-
-INHERIT_DOCS = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
-# new page for each member. If set to NO, the documentation of a member will be
-# part of the file/class/namespace that contains it.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE = 4
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:\n"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
-
-ALIASES =
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
-#
-# Note For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
-
-EXTENSION_MAPPING =
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: YES.
-
-MARKDOWN_SUPPORT = YES
-
-# When enabled doxygen tries to link words that correspond to documented
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by by putting a % sign in front of the word
-# or globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS = NO
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT = NO
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
-EXTRACT_ALL = NO
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
-EXTRACT_STATIC = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. When set to YES local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO these classes will be included in the various overviews. This option has
-# no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO these declarations will be
-# included in the documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: NO.
-
-STRICT_PROTO_MATCHING = NO
-
-# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
-# todo list. This list is created by putting \todo commands in the
-# documentation.
-# The default value is: YES.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
-# test list. This list is created by putting \test commands in the
-# documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES the list
-# will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE =
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. Do not use file names with spaces, bibtex cannot handle them. See
-# also \cite for info how to create references.
-
-CITE_BIB_FILES =
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED = YES
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO doxygen will only warn about wrong or incomplete parameter
-# documentation, but not about the absence of documentation.
-# The default value is: NO.
-
-WARN_NO_PARAMDOC = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
-# Note: If this tag is empty the current directory is searched.
-
-INPUT =
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
-# possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
-
-FILE_PATTERNS =
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS =
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-
-INPUT_FILTER =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-
-FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER ) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS =
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX = YES
-
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER =
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET =
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
-# defined cascading style sheet that is included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
-# Doxygen will copy the style sheet file to the output directory. For an example
-# see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the stylesheet and background images according to
-# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
-# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID = org.doxygen.Project
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP = NO
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE =
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler ( hhc.exe). If non-empty
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION =
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated (
-# YES) or that it should be included in the master .chm file ( NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI = NO
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING =
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated (
-# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
-# enables the Previous and Next buttons.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
-# folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME =
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS =
-
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID = org.doxygen.Project
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH = 250
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW = NO
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using prerendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX = NO
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS =
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
-# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
-# setting. When disabled, doxygen will generate a PHP script for searching and
-# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
-# and searching needs to be provided by external tools. See the section
-# "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
-# Searching" for details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL =
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID =
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX = YES
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE = a4
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
-#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
-# replace them by respectively the title of the page, the current date and time,
-# only the current date, the version number of doxygen, the project name (see
-# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER =
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS = YES
-
-# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES to get a
-# higher quality PDF documentation.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES = NO
-
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BIB_STYLE = plain
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION = .3
-
-# The MAN_SUBDIR tag determines the name of the directory created within
-# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
-# MAN_EXTENSION with the initial . removed.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_SUBDIR =
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT = xml
-
-# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT = docbook
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
-# Definitions (see http://autogen.sf.net) file that captures the structure of
-# the code including all documentation. Note that this feature is still
-# experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
-# in the source code. If set to NO only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES the includes files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro definition that overrules the
-# definition found in the source code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all references to function-like macros that are alone on a line, have
-# an all uppercase name, and do not end with a semicolon. Such function macros
-# are typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have a unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
-# class index. If set to NO only the inherited external classes will be listed.
-# The default value is: NO.
-
-ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
-# the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS = YES
-
-# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH =
-
-# If set to YES, the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
-HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: NO.
-
-HAVE_DOT = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS = 0
-
-# When you want a differently looking font n the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH =
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH = YES
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LIMIT_NUM_FIELDS = 10
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH = YES
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH = YES
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH = YES
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY = YES
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, jpg, gif and svg.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS =
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-DIAFILE_DIRS =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS = NO
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
-# files that are used to generate the various graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_CLEANUP = YES
+++ /dev/null
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
+++ /dev/null
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
+++ /dev/null
-#
-# Makefile for the SWAP
-#
-
-obj-$(CONFIG_SWAP_DA) += \
- master/ \
- buffer/ \
- ksyms/ \
- driver/ \
- writer/ \
- kprobe/ \
- uprobe/ \
- us_manager/ \
- ks_features/ \
- sampler/ \
- energy/ \
- parser/ \
- retprobe/ \
- webprobe/ \
- task_data/ \
- preload/ \
- fbiprobe/ \
- wsp/ \
- nsp/
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_buffer.o
-swap_buffer-y := swap_buffer_module.o \
- buffer_queue.o
-
+++ /dev/null
-/**
- * @file buffer/buffer_description.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * swap_subbuffer structure represents one buffers subbufer
- */
-
-#ifndef __BUFFER_DESCRIPTION_H__
-#define __BUFFER_DESCRIPTION_H__
-
-#include "data_types.h"
-
-/**
- * @struct swap_subbuffer
- * @brief This structures are combined in array which represents the SWAP buffer.
- * @var swap_subbuffer::next_in_queue
- * Pointer to the next swap_subbufer in queue
- * @var swap_subbuffer::full_buffer_part
- * Currently occupied subbuffers size
- * @var swap_subbuffer::data_buffer
- * Pointer to subbuffers data itself of type swap_subbuffer_ptr
- * @var swap_subbuffer::buffer_sync
- * Subbuffers sync primitive
- */
-struct swap_subbuffer {
- /* Pointer to the next subbuffer in queue */
- struct swap_subbuffer *next_in_queue;
- /* Size of the filled part of a subbuffer */
- size_t full_buffer_part;
- /* Pointer to data buffer */
- swap_subbuffer_ptr data_buffer;
- /* Buffer rw sync */
- struct sync_t buffer_sync;
-};
-
-#endif /* __BUFFER_DESCRIPTION_H__ */
+++ /dev/null
-/**
- * buffer/buffer_queue.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Implements buffers queues interface
- */
-
-/* For all memory allocation/deallocation operations, except buffer memory
- * allocation/deallocation should be used
- * memory_allocation(size_t memory_size)
- * memory_free(void *ptr)
- * defines.
- * For subbuffer allocation/deallocation operations should be used
- * buffer_allocation(size_t subbuffer_size)
- * buffer_free(void *ptr, size_t subbuffer_size)
- * To get buffer pointer for any usage, EXCEPT ALLOCATION AND DEALLOCATION
- * use the following define:
- * buffer_pointer(void *ptr_to_buffer_element_of_swap_buffer_structure)
- * DO NOT USE SUBBUFFER PTR IN STRUCT SWAP_BUFFER WITHOUT THIS DEFINE!
- * It will be ok for user space, but fail in kernel space.
- *
- * See space_dep_types_and_def.h for details */
-
-
-
-#include "buffer_queue.h"
-#include "swap_buffer_to_buffer_queue.h"
-#include "swap_buffer_errors.h"
-#include "kernel_operations.h"
-
-/**
- * @struct queue_t
- * @brief Queue structure. Consist of pointers to the first and the last
- * elements of queue.
- * @var queue_t::start_ptr
- * Pointer to the first subbuffer in queue
- * @var queue_t::end_ptr
- * Pointer to the last subbuffer in queue
- * @var queue_t::subbuffers_count
- * Subbuffers count in queue
- * @var queue_t::queue_sync
- * Queue access sync primitive
- */
-struct queue_t {
- struct swap_subbuffer *start_ptr;
- struct swap_subbuffer *end_ptr;
- unsigned int subbuffers_count;
- struct sync_t queue_sync;
-};
-
-/**
- * @var write_queue
- * @brief Represents write queue.
- */
-struct queue_t write_queue = {
- .start_ptr = NULL,
- .end_ptr = NULL,
- .subbuffers_count = 0,
- .queue_sync = {
- .flags = 0x0
- }
-};
-
-/**
- * @var read_queue
- * @brief Represents read queue.
- */
-struct queue_t read_queue = {
- .start_ptr = NULL,
- .end_ptr = NULL,
- .subbuffers_count = 0,
- .queue_sync = {
- .flags = 0x0
- }
-};
-
-/* Pointers array. Points to busy buffers */
-static struct swap_subbuffer **queue_busy;
-
-/* Store last busy element */
-static unsigned int queue_busy_last_element;
-
-/* Subbuffers count */
-static unsigned int queue_subbuffer_count;
-
-/* One subbuffer size */
-static size_t queue_subbuffer_size;
-
-/* Busy list sync */
-static struct sync_t buffer_busy_sync = {
- .flags = 0x0
-};
-
-/* Memory pages count in one subbuffer */
-static int pages_order_in_subbuffer;
-
-/**
- * @brief Allocates memory for swap_subbuffer structures and subbuffers.
- * Total allocated memory = subbuffer_size * subbuffers_count.
- *
- * @param subbuffer_size Size of each subbuffer.
- * @param subbuffers_count Count of subbuffers.
- * @return 0 on success, negative error code otherwise.
- */
-int buffer_queue_allocation(size_t subbuffer_size,
- unsigned int subbuffers_count)
-{
- unsigned int i = 0;
- unsigned int j = 0;
- unsigned int allocated_buffers = 0;
- unsigned int allocated_structs = 0;
- struct swap_subbuffer *clean_tmp_struct;
- int result;
-
- /* Static varibles initialization */
- queue_subbuffer_size = subbuffer_size;
- queue_subbuffer_count = subbuffers_count;
- queue_busy_last_element = 0;
-
- /* Set variable pages_in_subbuffer. It is used for allocation and
- * deallocation memory pages and its value is returned from
- * swap_buffer_get() and contains page count in one subbuffer.
- * All this useful only in kernel space. In userspace it is dummy.*/
- set_pages_order_in_subbuffer(queue_subbuffer_size);
- /* Sync primitives initialization */
- sync_init(&read_queue.queue_sync);
- sync_init(&write_queue.queue_sync);
- sync_init(&buffer_busy_sync);
-
- /* Memory allocation for queue_busy */
- queue_busy =
- memory_allocation(sizeof(*queue_busy) * queue_subbuffer_count);
-
- if (!queue_busy) {
- result = -E_SB_NO_MEM_QUEUE_BUSY;
- goto buffer_allocation_error_ret;
- }
-
- /* Memory allocation for swap_subbuffer structures */
-
- /* Allocation for first structure. */
- write_queue.start_ptr =
- memory_allocation(sizeof(*write_queue.start_ptr));
-
- if (!write_queue.start_ptr) {
- result = -E_SB_NO_MEM_BUFFER_STRUCT;
- goto buffer_allocation_queue_busy_free;
- }
- allocated_structs++;
-
-
- write_queue.end_ptr = write_queue.start_ptr;
-
- write_queue.end_ptr->next_in_queue = NULL;
- write_queue.end_ptr->full_buffer_part = 0;
- write_queue.end_ptr->data_buffer =
- buffer_allocation(queue_subbuffer_size);
- if (!write_queue.end_ptr->data_buffer) {
- print_err("Cannot allocate memory for buffer 1\n");
- result = -E_SB_NO_MEM_DATA_BUFFER;
- goto buffer_allocation_error_free;
- }
- allocated_buffers++;
-
- sync_init(&write_queue.end_ptr->buffer_sync);
-
- /* Buffer initialization */
- memset(buffer_address(write_queue.end_ptr->data_buffer), 0,
- queue_subbuffer_size);
-
- /* Allocation for other structures. */
- for (i = 1; i < queue_subbuffer_count; i++) {
- write_queue.end_ptr->next_in_queue =
- memory_allocation(
- sizeof(*write_queue.end_ptr->next_in_queue));
- if (!write_queue.end_ptr->next_in_queue) {
- result = -E_SB_NO_MEM_BUFFER_STRUCT;
- goto buffer_allocation_error_free;
- }
- allocated_structs++;
-
- /* Now next write_queue.end_ptr is next */
- write_queue.end_ptr = write_queue.end_ptr->next_in_queue;
-
- write_queue.end_ptr->next_in_queue = NULL;
- write_queue.end_ptr->full_buffer_part = 0;
- write_queue.end_ptr->data_buffer =
- buffer_allocation(queue_subbuffer_size);
- if (!write_queue.end_ptr->data_buffer) {
- result = -E_SB_NO_MEM_DATA_BUFFER;
- goto buffer_allocation_error_free;
- }
- allocated_buffers++;
-
- sync_init(&write_queue.end_ptr->buffer_sync);
-
- /* Buffer initialization */
- memset(buffer_address(write_queue.end_ptr->data_buffer), 0,
- queue_subbuffer_size);
- }
-
- /* All subbuffers are in write list */
- write_queue.subbuffers_count = subbuffers_count;
-
- return E_SB_SUCCESS;
-
- /* In case of errors, this code is called */
- /* Free all previously allocated memory */
-buffer_allocation_error_free:
- clean_tmp_struct = write_queue.start_ptr;
-
- for (j = 0; j < allocated_structs; j++) {
- clean_tmp_struct = write_queue.start_ptr;
- if (allocated_buffers) {
- buffer_free(clean_tmp_struct->data_buffer,
- queue_subbuffer_size);
- allocated_buffers--;
- }
- if (write_queue.start_ptr != write_queue.end_ptr)
- write_queue.start_ptr =
- write_queue.start_ptr->next_in_queue;
- memory_free(clean_tmp_struct);
- }
- write_queue.end_ptr = NULL;
- write_queue.start_ptr = NULL;
-
-buffer_allocation_queue_busy_free:
- memory_free(queue_busy);
- queue_busy = NULL;
-
-buffer_allocation_error_ret:
- return result;
-}
-
-/**
- * @brief Resets all subbuffers for writing.
- *
- * @return 0 on success, negative error code otherwise.
- */
-int buffer_queue_reset(void)
-{
- struct swap_subbuffer *buffer = read_queue.start_ptr;
-
- /* Check if there are some subbuffers in busy list.
- * If so - return error */
- if (get_busy_buffers_count())
- return -E_SB_UNRELEASED_BUFFERS;
-
- /* Lock read sync primitive */
- sync_lock(&read_queue.queue_sync);
-
- /* Set all subbuffers in read list to write list
- * and reinitialize them */
- while (read_queue.start_ptr) {
-
- /* Lock buffer sync primitive to prevent writing to buffer if it
- * had been selected for writing, but still wasn't wrote. */
- sync_lock(&buffer->buffer_sync);
-
- buffer = read_queue.start_ptr;
-
- /* If we reached end of the list */
- if (read_queue.start_ptr == read_queue.end_ptr)
- read_queue.end_ptr = NULL;
-
- read_queue.start_ptr = read_queue.start_ptr->next_in_queue;
-
- /* Reinit full buffer part */
- buffer->full_buffer_part = 0;
-
- add_to_write_list(buffer);
-
- /* Unlock buffer sync primitive */
- sync_unlock(&buffer->buffer_sync);
- }
-
- /* Unlock read primitive */
- sync_unlock(&read_queue.queue_sync);
-
- return E_SB_SUCCESS;
-}
-
-/**
- * @brief Free all allocated subbuffers.
- *
- * @return Void.
- */
-void buffer_queue_free(void)
-{
- struct swap_subbuffer *tmp = NULL;
-
- /* Lock all sync primitives to prevet accessing free memory */
- sync_lock(&write_queue.queue_sync);
- sync_lock(&read_queue.queue_sync);
- sync_lock(&buffer_busy_sync);
-
- /* Free buffers and structures memory that are in read list */
- while (read_queue.start_ptr) {
- tmp = read_queue.start_ptr;
- read_queue.start_ptr = read_queue.start_ptr->next_in_queue;
- buffer_free(tmp->data_buffer, queue_subbuffer_size);
- memory_free(tmp);
- }
-
- /* Free buffers and structures memory that are in read list */
- while (write_queue.start_ptr) {
- tmp = write_queue.start_ptr;
- write_queue.start_ptr = write_queue.start_ptr->next_in_queue;
- buffer_free(tmp->data_buffer, queue_subbuffer_size);
- memory_free(tmp);
- }
-
- /* Free busy_list */
- memory_free(queue_busy);
- queue_busy = NULL;
-
- queue_subbuffer_size = 0;
- queue_subbuffer_count = 0;
- read_queue.start_ptr = NULL;
- read_queue.end_ptr = NULL;
- write_queue.start_ptr = NULL;
- write_queue.end_ptr = NULL;
-
- /* Unlock all sync primitives */
- sync_unlock(&buffer_busy_sync);
- sync_unlock(&read_queue.queue_sync);
- sync_unlock(&write_queue.queue_sync);
-}
-
-static unsigned int is_buffer_enough(struct swap_subbuffer *subbuffer,
- size_t size)
-{
- /* XXX Think about checking full_buffer_part for correctness
- * (<queue_subbuffer_size). It should be true, but if isn't (due to
- * sources chaning, etc.) this function should be true! */
- return ((queue_subbuffer_size-subbuffer->full_buffer_part) >= size) ?
- 1 : 0;
-}
-
-static void next_queue_element(struct queue_t *queue)
-{
- /* If we reached the last elemenet, end pointer should point to NULL */
- if (queue->start_ptr == queue->end_ptr)
- queue->end_ptr = NULL;
-
- queue->start_ptr = queue->start_ptr->next_in_queue;
- --queue->subbuffers_count;
-}
-
-/**
- * @brief Get first subbuffer from read list.
- *
- * @return Pointer to swap_subbuffer
- */
-struct swap_subbuffer *get_from_read_list(void)
-{
- struct swap_subbuffer *result = NULL;
-
- /* Lock read sync primitive */
- sync_lock(&read_queue.queue_sync);
-
- if (read_queue.start_ptr == NULL) {
- result = NULL;
- goto get_from_read_list_unlock;
- }
-
- result = read_queue.start_ptr;
-
- next_queue_element(&read_queue);
-
-get_from_read_list_unlock:
- /* Unlock read sync primitive */
- sync_unlock(&read_queue.queue_sync);
-
- return result;
-}
-
-/**
- * @brief Add subbuffer to read list.
- *
- * @param subbuffer Pointer to the subbuffer to add.
- * @return Void.
- */
-void add_to_read_list(struct swap_subbuffer *subbuffer)
-{
- /* Lock read sync primitive */
- sync_lock(&read_queue.queue_sync);
-
- if (!read_queue.start_ptr)
- read_queue.start_ptr = subbuffer;
-
- if (read_queue.end_ptr) {
- read_queue.end_ptr->next_in_queue = subbuffer;
-
- read_queue.end_ptr = read_queue.end_ptr->next_in_queue;
- } else {
- read_queue.end_ptr = subbuffer;
- }
- read_queue.end_ptr->next_in_queue = NULL;
- ++read_queue.subbuffers_count;
-
- /* Unlock read sync primitive */
- sync_unlock(&read_queue.queue_sync);
-}
-
-static int add_to_read_list_with_callback(struct swap_subbuffer *subbuffer,
- bool wakeup)
-{
- int result = 0;
-
- add_to_read_list(subbuffer);
- /* TODO Handle ret value */
- result = swap_buffer_callback(subbuffer, wakeup);
-
- return result;
-}
-
-/**
- * @brief Returns subbuffers to read count.
- *
- * @return Count of subbuffers in read_queue.
- */
-unsigned int get_readable_buf_cnt(void)
-{
- return read_queue.subbuffers_count;
-}
-
-
-/**
- * @brief Get first writable subbuffer from write list.
- *
- * @param size Minimum amount of free space in subbuffer.
- * @param[out] ptr_to_write Pointer to the variable where pointer to the
- * beginning of memory for writing should be stored.
- * @return Found swap_subbuffer.
- */
-struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write,
- bool wakeup)
-{
- struct swap_subbuffer *result = NULL;
-
- /* Callbacks are called at the end of the function
- * to prevent deadlocks */
- struct queue_t callback_queue = {
- .start_ptr = NULL,
- .end_ptr = NULL,
- .queue_sync = {
- .flags = 0x0
- }
- };
- struct swap_subbuffer *tmp_buffer = NULL;
-
- /* Init pointer */
- *ptr_to_write = NULL;
-
- /* Lock write list sync primitive */
- sync_lock(&write_queue.queue_sync);
-
- while (write_queue.start_ptr) {
-
- /* We're found subbuffer */
- if (is_buffer_enough(write_queue.start_ptr, size)) {
-
- result = write_queue.start_ptr;
- *ptr_to_write =
- (void *)((unsigned long)
- (buffer_address(result->data_buffer)) +
- result->full_buffer_part);
-
- /* Add data size to full_buffer_part.
- * Very important to do it in
- * write_queue.queue_sync spinlock */
- write_queue.start_ptr->full_buffer_part += size;
-
- /* Lock rw sync.
- * Should be unlocked in swap_buffer_write() */
- sync_lock_no_flags(&result->buffer_sync);
- break;
- /* This subbuffer is not enough => it goes to read list */
- } else {
- result = write_queue.start_ptr;
-
- next_queue_element(&write_queue);
-
- /* Add to callback list */
- if (!callback_queue.start_ptr)
- callback_queue.start_ptr = result;
-
- if (callback_queue.end_ptr)
- callback_queue.end_ptr->next_in_queue = result;
- callback_queue.end_ptr = result;
- callback_queue.end_ptr->next_in_queue = NULL;
- result = NULL;
- }
- }
-
- /* Unlock write list sync primitive */
- sync_unlock(&write_queue.queue_sync);
-
- /* Adding buffers to read list and calling callbacks */
- for (tmp_buffer = NULL; callback_queue.start_ptr; ) {
- if (callback_queue.start_ptr == callback_queue.end_ptr)
- callback_queue.end_ptr = NULL;
-
- tmp_buffer = callback_queue.start_ptr;
- callback_queue.start_ptr =
- callback_queue.start_ptr->next_in_queue;
-
- add_to_read_list_with_callback(tmp_buffer, wakeup);
- }
-
- return result;
-}
-
-/**
- * @brief Add subbuffer to write list.
- *
- * @param subbuffer Pointer to the swap_subbuffer that should be stored.
- * @return Void.
- */
-void add_to_write_list(struct swap_subbuffer *subbuffer)
-{
- sync_lock(&write_queue.queue_sync);
-
- /* Reinitialize */
- subbuffer->full_buffer_part = 0;
-
- if (!write_queue.start_ptr)
- write_queue.start_ptr = subbuffer;
-
- if (write_queue.end_ptr) {
- write_queue.end_ptr->next_in_queue = subbuffer;
- write_queue.end_ptr = write_queue.end_ptr->next_in_queue;
- } else {
- write_queue.end_ptr = subbuffer;
- }
- write_queue.end_ptr->next_in_queue = NULL;
- ++write_queue.subbuffers_count;
-
- sync_unlock(&write_queue.queue_sync);
-}
-
-/**
- * @brief Returns subbuffers to write count.
- *
- * @return Count of subbuffers in write queue.
- */
-unsigned int get_writable_buf_cnt(void)
-{
- return write_queue.subbuffers_count;
-}
-
-
-/**
- * @brief Add subbuffer to busy list when it is read from out of the buffer.
- *
- * @param subbuffer Pointer to the swap_subbuffer that should be added.
- * @return Void.
- */
-void add_to_busy_list(struct swap_subbuffer *subbuffer)
-{
- /* Lock busy sync primitive */
- sync_lock(&buffer_busy_sync);
-
- subbuffer->next_in_queue = NULL;
- queue_busy[queue_busy_last_element] = subbuffer;
- queue_busy_last_element += 1;
-
- /* Unlock busy sync primitive */
- sync_unlock(&buffer_busy_sync);
-}
-
-/**
- * @brief Remove subbuffer from busy list when it is released.
- *
- * @param subbuffer Pointer to the swap_subbuffer that should be removed.
- * @return 0 on success, negative error code otherwise.
- */
-int remove_from_busy_list(struct swap_subbuffer *subbuffer)
-{
- int result = -E_SB_NO_SUBBUFFER_IN_BUSY; /* For sanitization */
- int i;
-
- /* Lock busy list sync primitive */
- sync_lock(&buffer_busy_sync);
-
- /* Sanitization and removing */
- for (i = 0; i < queue_busy_last_element; i++) {
- if (queue_busy[i] == subbuffer) {
- /* Last element goes here and length is down 1 */
- queue_busy[i] = queue_busy[queue_busy_last_element - 1];
- queue_busy_last_element -= 1;
- result = E_SB_SUCCESS;
- break;
- }
- }
-
- /* Unlock busy list sync primitive */
- sync_unlock(&buffer_busy_sync);
-
- return result;
-}
-
-/**
- * @brief Set all subbuffers in write list to read list.
- *
- * @return Void.
- */
-void buffer_queue_flush(void)
-{
- struct swap_subbuffer *buffer = write_queue.start_ptr;
-
- /* Locking write sync primitive */
- sync_lock(&write_queue.queue_sync);
-
- while (write_queue.start_ptr &&
- write_queue.start_ptr->full_buffer_part) {
-
- /* Lock buffer sync primitive to prevent writing to buffer if it
- * had been selected for writing, but still wasn't wrote. */
- sync_lock(&buffer->buffer_sync);
-
- buffer = write_queue.start_ptr;
- next_queue_element(&write_queue);
- add_to_read_list(buffer);
-
- /* Unlock buffer sync primitive */
- sync_unlock(&buffer->buffer_sync);
- }
-
- /* Unlock write primitive */
- sync_unlock(&write_queue.queue_sync);
-}
-
-/**
- * @brief Get subbuffers count in busy list.
- *
- * @return Count of swap_subbuffers in busy list.
- */
-int get_busy_buffers_count(void)
-{
- int result;
-
- sync_lock(&buffer_busy_sync);
- result = queue_busy_last_element;
- sync_unlock(&buffer_busy_sync);
-
- return result;
-}
-
-/**
- * @brief Get memory pages count in subbuffer.
- *
- * @return Pages count in subbuffer.
- */
-int get_pages_count_in_subbuffer(void)
-{
-/* Return 1 if pages order 0,
- * or 2 of power pages_order_in_subbuffer otherwise */
- return (pages_order_in_subbuffer) ?
- 2 << (pages_order_in_subbuffer - 1) : 1;
-}
+++ /dev/null
-/**
- * @file buffer/buffer_queue.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Represents buffers queues interface
- */
-
-/* SWAP Buffer queues interface */
-
-#ifndef __BUFFER_QUEUE_H__
-#define __BUFFER_QUEUE_H__
-
-#include <linux/types.h>
-#include "buffer_description.h"
-
-int buffer_queue_allocation(size_t subbuffer_size,
- unsigned int subbuffers_count);
-void buffer_queue_free(void);
-int buffer_queue_reset(void);
-void buffer_queue_flush(void);
-struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write,
- bool wakeup);
-struct swap_subbuffer *get_from_read_list(void);
-void add_to_write_list(struct swap_subbuffer *subbuffer);
-void add_to_read_list(struct swap_subbuffer *subbuffer);
-void add_to_busy_list(struct swap_subbuffer *subbuffer);
-int remove_from_busy_list(struct swap_subbuffer *subbuffer);
-
-unsigned int get_readable_buf_cnt(void);
-unsigned int get_writable_buf_cnt(void);
-int get_busy_buffers_count(void);
-int get_pages_count_in_subbuffer(void);
-
-#endif /* __BUFFER_QUEUE_H__ */
+++ /dev/null
-/**
- * @file buffer/data_types.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Declares data types for SWAP buffer.
- */
-
-#ifndef __DATA_TYPES_H__
-#define __DATA_TYPES_H__
-
-
-#include <linux/spinlock.h>
-
-
-struct page;
-
-/**
- * @struct sync_t
- * @brief Using spinlocks as sync primitives.
- * @var sync_t::spinlock
- * Spinlock.
- * @var sync_t::flags
- * Flags for spinlock.
- */
-struct sync_t {
- spinlock_t spinlock;
- unsigned long flags;
-};
-
-/**
- * @brief swap_subbuffer_ptr points to the first memory page of the subbuffer.
- */
-typedef struct page *swap_subbuffer_ptr;
-
-#endif /* __DATA_TYPES_H__ */
+++ /dev/null
-/**
- * @file buffer/kernel_operations.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Kernel functions wrap.
- */
-
-#ifndef __KERNEL_OPERATIONS_H__
-#define __KERNEL_OPERATIONS_H__
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/semaphore.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/mm.h>
-
-#include "data_types.h"
-
-
-/* MESSAGES */
-/** Prints debug message.*/
-#define print_debug(msg, args...) \
- printk(KERN_DEBUG "SWAP_BUFFER DEBUG : " msg, ##args)
-/** Prints info message.*/
-#define print_msg(msg, args...) \
- printk(KERN_INFO "SWAP_BUFFER : " msg, ##args)
-/** Prints warning message.*/
-#define print_warn(msg, args...) \
- printk(KERN_WARNING "SWAP_BUFFER WARNING : " msg, ##args)
-/** Prints error message.*/
-#define print_err(msg, args...) \
- printk(KERN_ERR "SWAP_BUFFER ERROR : " msg, ##args)
-/** Prints critical error message.*/
-#define print_crit(msg, args...) \
- printk(KERN_CRIT "SWAP_BUFFER CRITICAL : " msg, ##args)
-
-
-/**
- * @brief struct sync_t initialization.
- *
- * @param buffer_sync Target sync primitive.
- * @return Void.
- */
-static inline void sync_init(struct sync_t *buffer_sync)
-{
- spin_lock_init(&buffer_sync->spinlock);
-}
-
-/**
- * @brief Lock sync_t with saving flags.
- *
- * @param buffer_sync Target sync primitive.
- * @return Void.
- */
-static inline void sync_lock(struct sync_t *buffer_sync)
-{
- spin_lock_irqsave(&buffer_sync->spinlock, buffer_sync->flags);
-}
-
-/**
- * @brief Unlock sync_t with restoring flags.
- *
- * @param buffer_sync Target sync primitive.
- * @return Void.
- */
-static inline void sync_unlock(struct sync_t *buffer_sync)
-{
- spin_unlock_irqrestore(&buffer_sync->spinlock, buffer_sync->flags);
-}
-
-/**
- * @brief Lock sync_t without saving flags.
- *
- * @param buffer_sync Target sync primitive.
- * @return Void.
- */
-static inline void sync_lock_no_flags(struct sync_t *buffer_sync)
-{
- spin_lock(&buffer_sync->spinlock);
-}
-
-/**
- * @brief Unlock sync_t without restoring flags.
- *
- * @param buffer_sync Target sync primitive.
- * @return Void.
- */
-static inline void sync_unlock_no_flags(struct sync_t *buffer_sync)
-{
- spin_unlock(&buffer_sync->spinlock);
-}
-
-/**
- * @brief Disable preemption and irqs.
- *
- * @param flags Variable to save flags to.
- * @return Void.
- */
-static inline void swap_irq_disable(unsigned long *flags)
-{
- preempt_disable();
- local_irq_save(*flags);
-}
-
-/**
- * @brief Enable preemption and irqs.
- *
- * @param flags Variable to restore flags from.
- * @return Void.
- */
-static inline void swap_irq_enable(unsigned long *flags)
-{
- local_irq_restore(*flags);
- preempt_enable();
-}
-
-/* SWAP SUBBUFER */
-
-
-/* We alloc memory for swap_subbuffer structures with common kmalloc */
-/** Allocates memory for subbuffer structures.*/
-#define memory_allocation(memory_size) kmalloc(memory_size, GFP_KERNEL)
-/** Free subbuffer structures memory.*/
-#define memory_free(ptr) kfree(ptr)
-
-/** For subbuffers themselves, we allocate memory with alloc_pages, so, we have
- * to evaluate required pages order */
-#define buffer_allocation(memory_size) \
- alloc_pages(GFP_KERNEL, (pages_order_in_subbuffer >= 0) ? \
- pages_order_in_subbuffer : \
- get_order_for_alloc_pages(memory_size))
-
-/** Free buffer's memory.*/
-#define buffer_free(ptr, subbuf_size) \
- __free_pages(ptr, (pages_order_in_subbuffer >= 0) ? \
- pages_order_in_subbuffer : \
- get_order_for_alloc_pages(subbuf_size))
-
-/** Returns buffer address.*/
-#define buffer_address(buffer_ptr) page_address(buffer_ptr)
-/** Sets page order in subbuffer.*/
-#define set_pages_order_in_subbuffer(memory_size) \
- pages_order_in_subbuffer = get_order_for_alloc_pages(memory_size)
-
-/**
- * @brief Functions for pages allocation.
- *
- * @param number Target number.
- * @return Power of two.
- */
-static inline unsigned int nearest_power_of_two(unsigned int number)
-{
- unsigned int result = 0;
- unsigned int two_to_the_power = 1;
-
- /* If aligned_size == PAGE_SIZE we need only one page, so return 0 */
- if (number == 1)
- return result;
-
- while (two_to_the_power < number) {
- two_to_the_power <<= 1;
- result++;
- }
-
- return result;
-}
-
-/**
- * @brief Order for alloc pages.
- *
- * @param memory_size Wishful memory size.
- * @return Pages order.
- */
-static inline unsigned int get_order_for_alloc_pages(size_t memory_size)
-{
- /* First evaluate remainder of the division memory_size by PAGE_SIZE.
- * If memory_size is divisible by PAGE_SIZE, then remainder equals 0. */
- size_t remainder = (memory_size % PAGE_SIZE) ?
- (memory_size % PAGE_SIZE) : PAGE_SIZE;
-
- /* Align memory_size to the PAGE_SIZE. aligned_size >= memory_size */
- size_t aligned_size = memory_size + (PAGE_SIZE - remainder);
-
- return nearest_power_of_two(aligned_size / PAGE_SIZE);
-}
-
-#endif /* __KERNEL_OPERATIONS_H__ */
+++ /dev/null
-/**
- * @file buffer/swap_buffer_errors.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * SWAP Buffer error codes enumeration.
- */
-
-#ifndef __SWAP_BUFFER_ERRORS_H__
-#define __SWAP_BUFFER_ERRORS_H__
-
-/**
- * @enum _swap_buffer_errors
- * @brief SWAP buffer errors enumeration.
- */
-enum _swap_buffer_errors {
- /**
- * @brief Success.
- */
- E_SB_SUCCESS = 0,
- /**
- * @brief There are some unreleased buffers.
- * Mainly returned by swap_buffer_uninit.
- */
- E_SB_UNRELEASED_BUFFERS = 1,
- /**
- * @brief No buffers for writing.
- */
- E_SB_NO_WRITABLE_BUFFERS = 2,
- /**
- * @brief Wrong data size: size == 0 or size > subbuffer size.
- */
- E_SB_WRONG_DATA_SIZE = 3,
- /**
- * @brief Trying to write data after SWAP buffer has been stopped.
- */
- E_SB_IS_STOPPED = 4,
- /**
- * @brief Memory areas of data to be written and subbuffer itself
- * are overlap.
- */
- E_SB_OVERLAP = 5,
- /**
- * @brief No buffers for reading.
- */
- E_SB_NO_READABLE_BUFFERS = 6,
- /**
- * @brief Callback function ptr == NULL.
- */
- E_SB_NO_CALLBACK = 7,
- /**
- * @brief Memory for queue_busy wasn't allocated.
- */
- E_SB_NO_MEM_QUEUE_BUSY = 8,
- /**
- * @brief Memory for one of struct swap_buffer wasn't allocated.
- */
- E_SB_NO_MEM_BUFFER_STRUCT = 9,
- /**
- * @brief Memort for data buffer itself wasn't allocated.
- */
- E_SB_NO_MEM_DATA_BUFFER = 10,
- /**
- * @brief No such subbuffer in busy_list.
- */
- E_SB_NO_SUBBUFFER_IN_BUSY = 11,
- /**
- * @brief Subbuffers aren't allocated.
- */
- E_SB_NOT_ALLOC = 12,
- /**
- * @brief Thresholds > 100, top < lower.
- */
- E_SB_WRONG_THRESHOLD = 13
-};
-
-#endif /* __SWAP_BUFFER_ERRORS_H__ */
+++ /dev/null
-/**
- * buffer/swap_buffer_module.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * SWAP Buffer interface implementation.
- */
-
-#include "swap_buffer_module.h"
-#include "buffer_queue.h"
-#include "buffer_description.h"
-#include "swap_buffer_errors.h"
-#include "kernel_operations.h"
-
-/**
- * @enum _swap_buffer_status_mask
- * @brief Bitwise mask for buffer status.
- */
-enum _swap_buffer_status_mask {
- BUFFER_FREE = 0, /**< 000 - memory free. */
- BUFFER_ALLOC = 1, /**< 001 - memory allocated. */
- BUFFER_PAUSE = 2, /**< 010 - buffer overflow. */
- BUFFER_WORK = 4 /**< @brief 100 - buffer work. */
-};
-
-static unsigned char swap_buffer_status = BUFFER_FREE;
-
-/**
- * @brief Subbuffer callback type.
- */
-typedef int(*subbuffer_callback_type)(bool wakeup);
-
-/* Callback that is called when full subbuffer appears */
-static subbuffer_callback_type subbuffer_callback;
-
-/* One subbuffer size */
-static size_t subbuffers_size;
-
-/* Subbuffers count */
-static unsigned int subbuffers_num;
-
-static unsigned int enough_writable_bufs;
-static unsigned int min_writable_bufs;
-static int (*low_mem_cb)(void);
-static int (*enough_mem_cb)(void);
-
-
-static inline int areas_overlap(const void *area1,
- const void *area2,
- size_t size)
-{
- int i;
-
- for (i = 0; i < size; i++)
- if ((area1 + i == area2) || (area2 + i == area1))
- return 1;
-
- return 0;
-}
-
-static inline unsigned int percent_to_count(unsigned char percent,
- unsigned int cnt)
-{
- return (percent * cnt) / 100;
-}
-
-/**
- * @brief Initializes SWAP buffer and allocates memory.
- *
- * @param buf_init Pointer to the buffer_init_t structure which contains
- * information about subbuffers count, subbuffers size and subbuffer-full-
- * callback.
- * @return 0 on success, negative error code otherwise.
- */
-int swap_buffer_init(struct buffer_init_t *buf_init)
-{
- int result = -1;
-
- swap_buffer_status &= ~BUFFER_WORK;
- print_debug("status buffer stop = %d\n", swap_buffer_status);
-
- if ((buf_init->top_threshold > 100) ||
- (buf_init->lower_threshold > 100) ||
- (buf_init->top_threshold < buf_init->lower_threshold))
- return -E_SB_WRONG_THRESHOLD;
-
- min_writable_bufs = percent_to_count(buf_init->lower_threshold,
- buf_init->nr_subbuffers);
-
- enough_writable_bufs = percent_to_count(buf_init->top_threshold,
- buf_init->nr_subbuffers);
-
- low_mem_cb = buf_init->low_mem_cb;
- enough_mem_cb = buf_init->enough_mem_cb;
-
- if ((swap_buffer_status & BUFFER_ALLOC) &&
- (subbuffers_size == buf_init->subbuffer_size) &&
- (subbuffers_num == buf_init->nr_subbuffers) &&
- ((subbuffer_callback_type)subbuffer_callback ==
- buf_init->subbuffer_full_cb)) {
- result = buffer_queue_reset();
- goto swap_buffer_init_work;
- }
-
- subbuffer_callback = buf_init->subbuffer_full_cb;
- subbuffers_size = buf_init->subbuffer_size;
- subbuffers_num = buf_init->nr_subbuffers;
-
- result = buffer_queue_allocation(subbuffers_size, subbuffers_num);
- if (result < 0)
- return result;
-
- result = get_pages_count_in_subbuffer();
-
- swap_buffer_status |= BUFFER_ALLOC;
- print_debug("status buffer alloc = %d\n", swap_buffer_status);
-
-swap_buffer_init_work:
- swap_buffer_status |= BUFFER_WORK;
- print_debug("status buffer work = %d\n", swap_buffer_status);
-
- return result;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_init);
-
-/**
- * @brief Uninitializes SWAP buffer, releases allocated memory.
- *
- * @return 0 on success, negative error code otherwise.
- */
-int swap_buffer_uninit(void)
-{
- /* Check whether buffer is allocated */
- if (!(swap_buffer_status & BUFFER_ALLOC))
- return -E_SB_NOT_ALLOC;
-
- /* Stop buffer */
- swap_buffer_status &= ~BUFFER_WORK;
- print_debug("status buffer stop = %d\n", swap_buffer_status);
-
- /* Check whether all buffers are released */
- if (get_busy_buffers_count())
- return -E_SB_UNRELEASED_BUFFERS;
-
- /* Free */
- buffer_queue_free();
-
- subbuffer_callback = NULL;
- subbuffers_size = 0;
- subbuffers_num = 0;
- min_writable_bufs = 0;
- enough_writable_bufs = 0;
- low_mem_cb = NULL;
- enough_mem_cb = NULL;
-
- swap_buffer_status &= ~BUFFER_ALLOC;
- print_debug("status buffer dealloc = %d\n", swap_buffer_status);
-
- return E_SB_SUCCESS;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_uninit);
-
-/**
- * @brief Writes data to SWAP buffer.
- *
- * @param data Pointer to a data for writing.
- * @param size Size of a data for writing.
- * @return Size of written data on success, negative error code otherwise.
- */
-ssize_t swap_buffer_write(void *data, size_t size, bool wakeup)
-{
- int result = E_SB_SUCCESS;
- struct swap_subbuffer *buffer_to_write = NULL;
- void *ptr_to_write = NULL;
- unsigned long flags = 0;
-
- /* Size sanitization */
- if ((size > subbuffers_size) || (size == 0))
- return -E_SB_WRONG_DATA_SIZE;
-
- /* Check buffer status */
- if (!(swap_buffer_status & BUFFER_WORK))
- return -E_SB_IS_STOPPED;
-
- /* We're going to look for writable buffer, so disable irqs */
- swap_irq_disable(&flags);
-
- /* Get next write buffer and occupying semaphore */
- buffer_to_write = get_from_write_list(size, &ptr_to_write, wakeup);
- if (!buffer_to_write) {
- swap_irq_enable(&flags);
- return -E_SB_NO_WRITABLE_BUFFERS;
- }
-
- /* Check for overlapping */
- if (areas_overlap(ptr_to_write, data, size)) {
- result = -E_SB_OVERLAP;
- goto buf_write_sem_post;
- }
-
- /* Copy data to buffer */
- /* XXX Think of using memmove instead - useless, anyway overlapping
- * means that something went wrong. */
- memcpy(ptr_to_write, data, size);
-
- result = size;
-
- if ((get_writable_buf_cnt() < min_writable_bufs) &&
- !(swap_buffer_status & BUFFER_PAUSE)) {
- swap_buffer_status |= BUFFER_PAUSE;
- if (low_mem_cb != NULL)
- low_mem_cb();
- }
-
- /* Unlock sync (Locked in get_from_write_list()) and enable irqs */
-buf_write_sem_post:
- sync_unlock_no_flags(&buffer_to_write->buffer_sync);
- swap_irq_enable(&flags);
-
- return result;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_write);
-
-/**
- * @brief Gets pointer to subbuffer for reading.
- *
- * @param[out] subbuffer Pointer to a variable which points on target subbuffer.
- * @return 0 on success, negative error code otherwise.
- */
-int swap_buffer_get(struct swap_subbuffer **subbuffer)
-{
- int result = 0;
- struct swap_subbuffer *buffer_to_read = NULL;
-
- /* Check buffer status */
- if (!(swap_buffer_status & BUFFER_WORK))
- return -E_SB_IS_STOPPED;
-
- /* Get next read buffer */
- buffer_to_read = get_from_read_list();
- if (!buffer_to_read)
- return -E_SB_NO_READABLE_BUFFERS;
-
- /* Add to busy list */
- buffer_to_read->next_in_queue = NULL;
- add_to_busy_list(buffer_to_read);
-
- *subbuffer = buffer_to_read;
-
- result = get_pages_count_in_subbuffer();
-
- return result;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_get);
-
-/**
- * @brief Releases subbuffer after reading.
- *
- * @param subbuffer Subbuffer that should be released.
- * @return 0 on success, negative error code otherwise.
- */
-int swap_buffer_release(struct swap_subbuffer **subbuffer)
-{
- int result;
-
- /* Remove from busy list (includes sanitization) */
- result = remove_from_busy_list(*subbuffer);
- if (result < 0)
- return result;
-
- /* Add to write list */
- add_to_write_list(*subbuffer);
-
- if ((swap_buffer_status & BUFFER_PAUSE) &&
- (get_writable_buf_cnt() >= enough_writable_bufs)) {
- swap_buffer_status &= ~BUFFER_PAUSE;
- if (enough_mem_cb != NULL)
- enough_mem_cb();
- }
-
- return E_SB_SUCCESS;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_release);
-
-/**
- * @brief Sets all subbuffers for reading.
- *
- * @return Count of subbeffers for reading.
- */
-unsigned int swap_buffer_flush(void)
-{
- unsigned int result;
-
- /* Set all non-empty write buffers to read list */
- buffer_queue_flush();
-
- /* Get count of all full buffers */
- result = get_readable_buf_cnt();
-
- return result;
-}
-EXPORT_SYMBOL_GPL(swap_buffer_flush);
-
-/**
- * @brief Executes subbuffer-full-callback.
- *
- * @param buffer Pointer to the full subbuffer.
- * @return -E_SB_NO_CALLBACK if no callback is registered or callbacks ret
- * value otherwise.
- */
-int swap_buffer_callback(void *buffer, bool wakeup)
-{
- int result;
-
- if (!subbuffer_callback)
- return -E_SB_NO_CALLBACK;
-
- result = subbuffer_callback(wakeup);
- if (result < 0)
- print_err("Callback error! Error code: %d\n", result);
-
- return result;
-}
-
-static int __init swap_buffer_module_init(void)
-{
- printk(KERN_NOTICE "SWAP_BUFFER : Buffer module initialized\n");
- return E_SB_SUCCESS;
-}
-
-static void __exit swap_buffer_module_exit(void)
-{
- if (swap_buffer_status & BUFFER_ALLOC)
- swap_buffer_uninit();
- printk(KERN_NOTICE "SWAP_BUFFER : Buffer module unintialized\n");
-}
-
-module_init(swap_buffer_module_init);
-module_exit(swap_buffer_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP buffer module");
-MODULE_AUTHOR("Aksenov A.S.");
+++ /dev/null
-/**
- * @file buffer/swap_buffer_module.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * SWAP Buffer interface declaration.
- */
-
-#ifndef __SWAP_BUFFER_MODULE_H__
-#define __SWAP_BUFFER_MODULE_H__
-
-#include <linux/types.h>
-
-struct swap_subbuffer;
-
-/**
- * @struct buffer_init_t
- * @brief Buffer init structure. Contains information necessary for SWAP buffer
- * initialization.
- * @var buffer_init_t::subbuffer_size
- * Subbuffer size.
- * @var buffer_init_t::nr_subbuffers
- * Subbuffers count.
- * @var buffer_init_t::subbuffer_full_cb
- * Callback. Called when one of subbuffers is full.
- * @var buffer_init_t::lower_threshold
- * Lower threshold in percent. When buffers fall below this limit
- * low_mem_cb is called and swap_buffer is suspended.
- * @var buffer_init_t::low_mem_cb
- * Callback that is called when count of free subbuffers falls below
- * lower_threshold.
- * @var buffer_init_t::top_threshold
- * Top threshold in percent. When buffers exceed this limit
- * enough_mem_cb is called.
- * @var buffer_init_t::enough_mem_cb
- * Callback that is called when count of free subbuffers exceeds top_threshold.
- */
-
-struct buffer_init_t {
- size_t subbuffer_size;
- unsigned int nr_subbuffers;
- int (*subbuffer_full_cb)(bool wakeup);
-
- unsigned char lower_threshold;
- int (*low_mem_cb)(void);
-
- unsigned char top_threshold;
- int (*enough_mem_cb)(void);
-};
-
-/* SWAP Buffer initialization function. Call it before using buffer.
- * Returns memory pages count (>0) in one subbuffer on success, or error code
- * (<0) otherwise. */
-int swap_buffer_init(struct buffer_init_t *buf_init);
-
-/* SWAP Buffer uninitialization function. Call it every time before removing
- * this module.
- * Returns E_SB_SUCCESS (0) on success, otherwise error code. */
-int swap_buffer_uninit(void);
-
-/* SWAP Buffer write function. Pass it size of the data and pointer to the data.
- * On success returns number of bytes written (>=0) or error code (<0)
- * otherwise */
-ssize_t swap_buffer_write(void *data, size_t size, bool wakeup);
-
-/* SWAP Buffer get. Put subbuffer pointer to the variable *subbuffer.
- * Return pages count in subbuffer. */
-int swap_buffer_get(struct swap_subbuffer **subbuffer);
-
-/* SWAP Buffer release. All 'get' buffers must be released with this function.
- * Just pass &subbuffer_ptr to it */
-int swap_buffer_release(struct swap_subbuffer **subbuffer);
-
-/* SWAP Buffer flush. Puts all buffers to read queue and returns their count. */
-unsigned int swap_buffer_flush(void);
-
-#endif /* __SWAP_BUFFER_MODULE_H__ */
+++ /dev/null
-/**
- * @file buffer/swap_buffer_to_buffer_queue.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- * SWAP Buffer interface for buffer queue.
- */
-
-#ifndef __SWAP_BUFFER_TO_BUFFER_QUEUE_H__
-#define __SWAP_BUFFER_TO_BUFFER_QUEUE_H__
-
-#include <linux/types.h>
-
-int swap_buffer_callback(void *buffer, bool wakeup);
-
-#endif /* __SWAP_BUFFER_TO_BUFFER_QUEUE_H__ */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_driver.o
-swap_driver-y := swap_driver_module.o \
- device_driver.o \
- driver_to_buffer.o
-
-ifeq ($(CONFIG_CONNECTOR),y)
- swap_driver-y += us_interaction.o
-endif
+++ /dev/null
-/**
- * @file driver/app_manage.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * Driver user <-> kernel connect implement.
- */
-
-#ifndef __APP_MANAGE_H__
-#define __APP_MANAGE_H__
-
-#include "us_interaction.h"
-#include "us_interaction_msg.h"
-
-/**
- * @brief Sends pause message to kernel.
- *
- * @return us_interaction_send_msg result.
- */
-static inline int app_manage_pause_apps(void)
-{
- enum us_interaction_k2u_msg_t us_int_msg = US_INT_PAUSE_APPS;
-
- return us_interaction_send_msg(&us_int_msg, sizeof(us_int_msg));
-}
-
-/**
- * @brief Sends continue message to kernel.
- *
- * @return us_interaction_send_msg result.
- */
-static inline int app_manage_cont_apps(void)
-{
- enum us_interaction_k2u_msg_t us_int_msg = US_INT_CONT_APPS;
-
- return us_interaction_send_msg(&us_int_msg, sizeof(us_int_msg));
-}
-
-#endif /* __APP_MANAGE_H__ */
+++ /dev/null
-/**
- * driver/device_driver.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Provides SWAP device.
- */
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/splice.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/uaccess.h>
-
-#include <ksyms/ksyms.h>
-#include <master/swap_initializer.h>
-
-#include "device_driver.h"
-#include "swap_driver_errors.h"
-#include "driver_to_buffer.h"
-#include "swap_ioctl.h"
-#include "driver_defs.h"
-#include "device_driver_to_driver_to_buffer.h"
-#include "driver_to_buffer.h"
-#include "driver_to_msg.h"
-
-/** SWAP device name as it is in /dev/. */
-#define SWAP_DEVICE_NAME "swap_device"
-
-/** Maximum subbuffer size. Used for sanitization checks. */
-#define MAXIMUM_SUBBUFFER_SIZE (64 * 1024)
-
-/* swap_device driver routines */
-static ssize_t swap_device_read(struct file *filp, char __user *buf,
- size_t count, loff_t *f_pos);
-static long swap_device_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg);
-static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
- unsigned int flags);
-
-/**
- * @var swap_device_fops
- * @brief SWAP device file operations.
- */
-const struct file_operations swap_device_fops = {
- .owner = THIS_MODULE,
- .read = swap_device_read,
- .open = swap_init_simple_open,
- .release = swap_init_simple_release,
- .unlocked_ioctl = swap_device_ioctl,
- .splice_read = swap_device_splice_read,
-};
-
-/* Typedefs for splice_* funcs. Prototypes are for linux-3.8.6 */
-/** Splice to pipe pointer type. */
-typedef ssize_t(*splice_to_pipe_p_t)(struct pipe_inode_info *pipe,
- struct splice_pipe_desc *spd);
-/** Splice grow spd pointer type. */
-typedef int(*splice_grow_spd_p_t)(const struct pipe_inode_info *pipe,
- struct splice_pipe_desc *spd);
-
-static splice_to_pipe_p_t splice_to_pipe_p;
-static splice_grow_spd_p_t splice_grow_spd_p;
-
-static msg_handler_t msg_handler;
-
-/* Device numbers */
-static dev_t swap_device_no;
-
-/* Device cdev struct */
-static struct cdev *swap_device_cdev;
-
-/* Device class struct */
-static struct class *swap_device_class;
-
-/* Device device struct */
-static struct device *swap_device_device;
-
-/* Reading tasks queue */
-static DECLARE_WAIT_QUEUE_HEAD(swap_device_wait);
-
-
-static atomic_t flag_wake_up = ATOMIC_INIT(0);
-
-static void __bottom_wake_up(void)
-{
- if (waitqueue_active(&swap_device_wait))
- wake_up_interruptible(&swap_device_wait);
-}
-
-static void bottom_wake_up(struct work_struct *work)
-{
- if (atomic_read(&flag_wake_up)) {
- atomic_set(&flag_wake_up, 0);
- __bottom_wake_up();
- }
-}
-
-static DECLARE_WORK(w_wake_up, bottom_wake_up);
-
-static void exit_w_wake_up(void)
-{
- flush_scheduled_work();
- __bottom_wake_up();
-}
-
-
-/**
- * @brief We need this realization of splice_shrink_spd() because its desing
- * frequently changes in custom kernels.
- *
- * @param pipe Pointer to the pipe whereto splice data.
- * @param spd Pointer to the splice_pipe_desc structure.
- * @return Void.
- */
-void swap_device_splice_shrink_spd(struct pipe_inode_info *pipe,
- struct splice_pipe_desc *spd)
-{
- if (pipe->buffers <= PIPE_DEF_BUFFERS)
- return;
-
- kfree(spd->pages);
- kfree(spd->partial);
-}
-
-
-/* TODO Think of permanent major */
-
-/**
- * @brief Register device.
- *
- * @return 0 on success, negative error code otherwise.
- */
-int swap_device_init(void)
-{
- int result;
-
- /* Allocating device major and minor nums for swap_device */
- result = alloc_chrdev_region(&swap_device_no, 0, 1, SWAP_DEVICE_NAME);
- if (result < 0) {
- print_crit("Major number allocation has failed\n");
- result = -E_SD_ALLOC_CHRDEV_FAIL;
- goto init_fail;
- }
-
- /* Creating device class. Using IS_ERR, because class_create
- * returns ERR_PTR on error. */
- swap_device_class = class_create(THIS_MODULE, SWAP_DEVICE_NAME);
- if (IS_ERR(swap_device_class)) {
- print_crit("Class creation has failed\n");
- result = -E_SD_CLASS_CREATE_FAIL;
- goto init_fail;
- }
-
- /* Cdev allocation */
- swap_device_cdev = cdev_alloc();
- if (!swap_device_cdev) {
- print_crit("Cdev structure allocation has failed\n");
- result = -E_SD_CDEV_ALLOC_FAIL;
- goto init_fail;
- }
-
- /* Cdev intialization and setting file operations */
- cdev_init(swap_device_cdev, &swap_device_fops);
-
- /* Adding cdev to system */
- result = cdev_add(swap_device_cdev, swap_device_no, 1);
- if (result < 0) {
- print_crit("Device adding has failed\n");
- result = -E_SD_CDEV_ADD_FAIL;
- goto init_fail;
- }
-
- /* Create device struct */
- swap_device_device = device_create(swap_device_class, NULL,
- swap_device_no,
- "%s", SWAP_DEVICE_NAME);
- if (IS_ERR(swap_device_device)) {
- print_crit("Device struct creating has failed\n");
- result = -E_SD_DEVICE_CREATE_FAIL;
- goto init_fail;
- }
-
- /* Find splice_* funcs addresses */
- splice_to_pipe_p = (splice_to_pipe_p_t)swap_ksyms("splice_to_pipe");
- if (!splice_to_pipe_p) {
- print_err("splice_to_pipe() not found!\n");
- result = -E_SD_NO_SPLICE_FUNCS;
- goto init_fail;
- }
-
- splice_grow_spd_p = (splice_grow_spd_p_t)swap_ksyms("splice_grow_spd");
- if (!splice_grow_spd_p) {
- print_err("splice_grow_spd() not found!\n");
- result = -E_SD_NO_SPLICE_FUNCS;
- goto init_fail;
- }
-
- return 0;
-
-init_fail:
- if (swap_device_cdev)
- cdev_del(swap_device_cdev);
- if (swap_device_class)
- class_destroy(swap_device_class);
- if (swap_device_no)
- unregister_chrdev_region(swap_device_no, 1);
- return result;
-}
-
-/* TODO Check wether driver is registered */
-
-/**
- * @brief Unregister device.
- *
- * @return Void.
- */
-void swap_device_exit(void)
-{
- exit_w_wake_up();
-
- splice_to_pipe_p = NULL;
- splice_grow_spd_p = NULL;
-
- device_destroy(swap_device_class, swap_device_no);
- cdev_del(swap_device_cdev);
- class_destroy(swap_device_class);
- unregister_chrdev_region(swap_device_no, 1);
-}
-
-static ssize_t swap_device_read(struct file *filp, char __user *buf,
- size_t count, loff_t *f_pos)
-{
- /* Wait queue item that consists current task. It is used to be added in
- * swap_device_wait queue if there is no data to be read. */
- DEFINE_WAIT(wait);
- int result;
-
- /* TODO : Think about spin_locks to prevent reading race condition. */
- while ((result =
- driver_to_buffer_next_buffer_to_read()) != E_SD_SUCCESS) {
-
- /* Add process to the swap_device_wait queue and set the current
- * task state TASK_INTERRUPTIBLE. If there is any data to be
- * read, then the current task is removed from the
- * swap_device_wait queue and its state is changed to this. */
- prepare_to_wait(&swap_device_wait, &wait, TASK_INTERRUPTIBLE);
-
- if (result < 0) {
- result = 0;
- goto swap_device_read_error;
- } else if (result == E_SD_NO_DATA_TO_READ) {
- /* Yes, E_SD_NO_DATA_TO_READ should be positive,
- * cause it's not really an error */
- if (filp->f_flags & O_NONBLOCK) {
- result = -EAGAIN;
- goto swap_device_read_error;
- }
- if (signal_pending(current)) {
- result = -ERESTARTSYS;
- goto swap_device_read_error;
- }
- schedule();
- finish_wait(&swap_device_wait, &wait);
- }
- }
-
- result = driver_to_buffer_read(buf, count);
- /* If there is an error - return 0 */
- if (result < 0)
- result = 0;
-
-
- return result;
-
-swap_device_read_error:
- finish_wait(&swap_device_wait, &wait);
-
- return result;
-}
-
-static long swap_device_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg)
-{
- int result;
-
- switch (cmd) {
- case SWAP_DRIVER_BUFFER_INITIALIZE:
- {
- struct buffer_initialize initialize_struct;
-
- result = copy_from_user(&initialize_struct, (void *)arg,
- sizeof(struct buffer_initialize));
- if (result)
- break;
-
- if (initialize_struct.size > MAXIMUM_SUBBUFFER_SIZE) {
- print_err("Wrong subbuffer size\n");
- result = -E_SD_WRONG_ARGS;
- break;
- }
-
- result = driver_to_buffer_initialize(initialize_struct.size,
- initialize_struct.count);
- if (result < 0) {
- print_err("Buffer initialization failed %d\n", result);
- break;
- }
- result = E_SD_SUCCESS;
-
- break;
- }
- case SWAP_DRIVER_BUFFER_UNINITIALIZE:
- {
- result = driver_to_buffer_uninitialize();
- if (result < 0)
- print_err("Buffer uninitialization failed %d\n",
- result);
- break;
- }
- case SWAP_DRIVER_NEXT_BUFFER_TO_READ:
- {
- /* Use this carefully */
- result = driver_to_buffer_next_buffer_to_read();
- if (result == E_SD_NO_DATA_TO_READ) {
- /* TODO Do what we usually do when there are no
- * subbuffers to read (make daemon sleep ?) */
- }
- break;
- }
- case SWAP_DRIVER_FLUSH_BUFFER:
- {
- result = driver_to_buffer_flush();
- break;
- }
- case SWAP_DRIVER_MSG:
- {
- if (msg_handler) {
- result = msg_handler((void __user *)arg);
- } else {
- print_warn("msg_handler() is not register\n");
- result = -EINVAL;
- }
- break;
- }
- case SWAP_DRIVER_WAKE_UP:
- {
- swap_device_wake_up_process();
- result = E_SD_SUCCESS;
- break;
- }
- default:
- print_warn("Unknown command %d\n", cmd);
- result = -EINVAL;
- break;
-
- }
- return result;
-}
-
-static void swap_device_pipe_buf_release(struct pipe_inode_info *inode,
- struct pipe_buffer *pipe)
-{
- __free_page(pipe->page);
-}
-
-static void swap_device_page_release(struct splice_pipe_desc *spd,
- unsigned int i)
-{
- __free_page(spd->pages[i]);
-}
-
-static const struct pipe_buf_operations swap_device_pipe_buf_ops = {
- .can_merge = 0,
- .map = generic_pipe_buf_map,
- .unmap = generic_pipe_buf_unmap,
- .confirm = generic_pipe_buf_confirm,
- .release = swap_device_pipe_buf_release,
- .steal = generic_pipe_buf_steal,
- .get = generic_pipe_buf_get
-};
-
-static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos,
- struct pipe_inode_info *pipe,
- size_t len, unsigned int flags)
-{
- /* Wait queue item that consists current task. It is used to be added in
- * swap_device_wait queue if there is no data to be read. */
- DEFINE_WAIT(wait);
-
- int result;
- struct page *pages[PIPE_DEF_BUFFERS];
- struct partial_page partial[PIPE_DEF_BUFFERS];
- struct splice_pipe_desc spd = {
- .pages = pages,
- .partial = partial,
- .nr_pages_max = PIPE_DEF_BUFFERS,
- .nr_pages = 0,
- .flags = flags,
- .ops = &swap_device_pipe_buf_ops,
- .spd_release = swap_device_page_release,
- };
-
- /* Get next buffer to read */
- /* TODO : Think about spin_locks to prevent reading race condition.*/
- while ((result =
- driver_to_buffer_next_buffer_to_read()) != E_SD_SUCCESS) {
-
- /* Add process to the swap_device_wait queue and set the current
- * task state TASK_INTERRUPTIBLE. If there is any data to be
- * read, then the current task is removed from the
- * swap_device_wait queue and its state is changed. */
- prepare_to_wait(&swap_device_wait, &wait, TASK_INTERRUPTIBLE);
- if (result < 0) {
- print_err("driver_to_buffer_next_buffer_to_read error "
- "%d\n", result);
- /* TODO Error return to OS */
- result = 0;
- goto swap_device_splice_read_error;
- } else if (result == E_SD_NO_DATA_TO_READ) {
- if (filp->f_flags & O_NONBLOCK) {
- result = -EAGAIN;
- goto swap_device_splice_read_error;
- }
- if (signal_pending(current)) {
- result = -ERESTARTSYS;
- goto swap_device_splice_read_error;
- }
- schedule();
- finish_wait(&swap_device_wait, &wait);
- }
- }
-
- if (splice_grow_spd_p(pipe, &spd)) {
- result = -ENOMEM;
- goto swap_device_splice_read_out;
- }
-
- result = driver_to_buffer_fill_spd(&spd);
- if (result != 0) {
- print_err("Cannot fill spd for splice\n");
- goto swap_device_shrink_spd;
- }
-
- result = splice_to_pipe_p(pipe, &spd);
-
-swap_device_shrink_spd:
- swap_device_splice_shrink_spd(pipe, &spd);
-
-swap_device_splice_read_out:
- return result;
-
-swap_device_splice_read_error:
- finish_wait(&swap_device_wait, &wait);
-
- return result;
-}
-
-/**
- * @brief Wakes up daemon that splicing data from driver.
- *
- * @return Void.
- */
-void swap_device_wake_up_process(void)
-{
- if (atomic_read(&flag_wake_up) == 0) {
- atomic_set(&flag_wake_up, 1);
- schedule_work(&w_wake_up);
- }
-}
-
-/**
- * @brief Registers received message handler.
- *
- * @param mh Pointer to message handler.
- * @return Void.
- */
-void set_msg_handler(msg_handler_t mh)
-{
- msg_handler = mh;
-}
-EXPORT_SYMBOL_GPL(set_msg_handler);
+++ /dev/null
-/**
- * @file driver/device_driver.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * SWAP device driver interface declaration.
- */
-
-#ifndef __SWAP_DRIVER_DEVICE_DRIVER_H__
-#define __SWAP_DRIVER_DEVICE_DRIVER_H__
-
-/* Create and register device */
-int swap_device_init(void);
-
-/* Delete device */
-void swap_device_exit(void);
-
-#endif /* __SWAP_DRIVER_DEVICE_DRIVER_H__ */
+++ /dev/null
-/**
- * @file device_driver_to_driver_to_buffer.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- * SWAP device interface for driver_to_buffer.
- */
-
-
-#ifndef __DEVICE_DRIVER_TO_DRIVER_TO_BUFFER_H__
-#define __DEVICE_DRIVER_TO_DRIVER_TO_BUFFER_H__
-
-void swap_device_wake_up_process(void);
-
-#endif /* __DEVICE_DRIVER_TO_DRIVER_TO_BUFFER_H__ */
+++ /dev/null
-/**
- * @file driver/driver_defs.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- * Device driver defs.
- */
-
-#ifndef __SWAP_DRIVER_DEVICE_DEFS_H__
-#define __SWAP_DRIVER_DEVICE_DEFS_H__
-
-#include <linux/kernel.h>
-
-/** Prints debug message.*/
-#define print_debug(msg, args...) \
- printk(KERN_DEBUG "SWAP_DRIVER DEBUG : " msg, ##args)
-/** Prints info message.*/
-#define print_msg(msg, args...) \
- printk(KERN_INFO "SWAP_DRIVER : " msg, ##args)
-/** Prints warning message.*/
-#define print_warn(msg, args...) \
- printk(KERN_WARNING "SWAP_DRIVER WARNING : " msg, ##args)
-/** Prints error message.*/
-#define print_err(msg, args...) \
- printk(KERN_ERR "SWAP_DRIVER ERROR : " msg, ##args)
-/** Prints critical error message.*/
-#define print_crit(msg, args...) \
- printk(KERN_CRIT "SWAP_DRIVER CRITICAL : " msg, ##args)
-
-#endif /* __SWAP_DRIVER_DEVICE_DEFS_H__ */
+++ /dev/null
-/**
- * driver/driver_to_buffer.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Driver and buffer interaction interface implementation.
- */
-
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/splice.h>
-#include <linux/uaccess.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-
-#include <buffer/swap_buffer_module.h>
-#include <buffer/swap_buffer_errors.h>
-#include <buffer/buffer_description.h>
-
-#include "driver_defs.h"
-#include "swap_driver_errors.h"
-#include "device_driver_to_driver_to_buffer.h"
-#include "app_manage.h"
-
-/* Current busy buffer */
-static struct swap_subbuffer *busy_buffer;
-
-/* Buffers count ready to be read */
-static int buffers_to_read;
-
-/* Pages count in one subbuffer */
-static int pages_per_buffer;
-
-/* Used to sync changes of the buffers_to_read var */
-static spinlock_t buf_to_read;
-
-
-static inline void init_buffers_to_read(void)
-{
- spin_lock_init(&buf_to_read);
- buffers_to_read = 0;
-}
-
-static inline void inc_buffers_to_read(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&buf_to_read, flags);
- buffers_to_read++;
- spin_unlock_irqrestore(&buf_to_read, flags);
-}
-
-static inline void dec_buffers_to_read(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&buf_to_read, flags);
- buffers_to_read--;
- spin_unlock_irqrestore(&buf_to_read, flags);
-}
-
-static inline void set_buffers_to_read(int count)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&buf_to_read, flags);
- buffers_to_read = count;
- spin_unlock_irqrestore(&buf_to_read, flags);
-}
-
-static inline int something_to_read(void)
-{
- unsigned long flags;
- int result;
-
- spin_lock_irqsave(&buf_to_read, flags);
- result = buffers_to_read;
- spin_unlock_irqrestore(&buf_to_read, flags);
-
- return result;
-}
-
-/* TODO Get subbuffer for reading */
-static size_t driver_to_buffer_get(void)
-{
- int result;
-
- /* If there is no readable buffers, return error */
- result = swap_buffer_get(&busy_buffer);
- if (result == -E_SB_NO_READABLE_BUFFERS) {
- busy_buffer = NULL;
- return -E_SD_NO_DATA_TO_READ;
- } else if (result < 0) {
- print_err("swap_buffer_get unhandle error %d\n", result);
- return -E_SD_BUFFER_ERROR;
- }
-
- return busy_buffer->full_buffer_part;
-}
-
-/* TODO Release subbuffer */
-static int driver_to_buffer_release(void)
-{
- int result;
-
- if (!busy_buffer)
- return -E_SD_NO_BUSY_SUBBUFFER;
-
- result = swap_buffer_release(&busy_buffer);
- if (result == -E_SB_NO_SUBBUFFER_IN_BUSY) {
- return -E_SD_WRONG_SUBBUFFER_PTR;
- } else if (result < 0) {
- print_err("swap_buffer_release unhandle error %d\n", result);
- return -E_SD_BUFFER_ERROR;
- }
-
- busy_buffer = NULL;
-
- return E_SD_SUCCESS;
-}
-
-static int driver_to_buffer_callback(bool wakeup)
-{
- /* Increment buffers_to_read counter */
- inc_buffers_to_read();
- if (wakeup)
- swap_device_wake_up_process();
-
- return E_SD_SUCCESS;
-}
-
-/**
- * @brief Copies data from subbuffer to userspace.
- *
- * @param[out] buf Pointer to userspace memory area whereto copy data from
- * subbuffer.
- * @param count Size of data to be read.
- * @return Read data size on success, negative error code on error.
- */
-ssize_t driver_to_buffer_read(char __user *buf, size_t count)
-{
- size_t bytes_to_copy;
- size_t bytes_to_read = 0;
- int page_counter = 0;
-
- /* Reading from swap_device means reading only current busy_buffer.
- * So, if there is no busy_buffer, we don't get next to read, we just
- * read nothing. In this case, or if there is nothing to read from
- * busy_buffer - return -E_SD_NO_DATA_TO_READ. It should be correctly
- * handled in device_driver */
- if (!busy_buffer || !busy_buffer->full_buffer_part)
- return -E_SD_NO_DATA_TO_READ;
-
- /* Bytes count that we're going to copy to user buffer is equal to user
- * buffer size or to subbuffer readable size whichever is less */
- bytes_to_copy = (count > busy_buffer->full_buffer_part) ?
- busy_buffer->full_buffer_part : count;
-
- /* Copy data from each page to buffer */
- while (bytes_to_copy > 0) {
- /* Get size that should be copied from current page */
- size_t read_from_this_page =
- (bytes_to_copy > PAGE_SIZE) ? PAGE_SIZE
- : bytes_to_copy;
-
- /* Copy and add size to copied bytes count */
-
- /* TODO Check with more than one page */
- bytes_to_read += read_from_this_page -
- copy_to_user(
- buf, page_address(busy_buffer->data_buffer) +
- (sizeof(struct page *) *
- page_counter),
- read_from_this_page);
- bytes_to_copy -= read_from_this_page;
- page_counter++;
- }
-
- return bytes_to_read;
-}
-
-/**
- * @brief Flushes SWAP buffer.
- *
- * @return 0.
- */
-int driver_to_buffer_flush(void)
-{
- unsigned int flushed;
-
- flushed = swap_buffer_flush();
- set_buffers_to_read(flushed);
- swap_device_wake_up_process();
-
- return E_SD_SUCCESS;
-}
-
-/**
- * @brief Fills spd structure.
- *
- * @param[out] spd Pointer to the splice_pipe_desc struct that should be filled.
- * @return 0 on success, negative error code on error.
- */
-int driver_to_buffer_fill_spd(struct splice_pipe_desc *spd)
-{
- size_t data_to_splice = busy_buffer->full_buffer_part;
- struct page **pages = spd->pages;
- struct partial_page *partial = spd->partial;
-
- while (data_to_splice) {
- size_t read_from_current_page = min(data_to_splice,
- (size_t)PAGE_SIZE);
-
- pages[spd->nr_pages] = alloc_page(GFP_KERNEL);
- if (!pages[spd->nr_pages]) {
- print_err("Cannot alloc page for splice\n");
- return -ENOMEM;
- }
-
- /* FIXME: maybe there is more efficient way */
- memcpy(page_address(pages[spd->nr_pages]),
- page_address(&busy_buffer->data_buffer[spd->nr_pages]),
- read_from_current_page);
-
- /* Always beginning of the page */
- partial[spd->nr_pages].offset = 0;
- partial[spd->nr_pages].len = read_from_current_page;
-
- /* Private is not used */
- partial[spd->nr_pages].private = 0;
-
- spd->nr_pages++;
- data_to_splice -= read_from_current_page;
-
- /* TODO: add check for pipe->buffers exceeding */
- /* if (spd->nr_pages == pipe->buffers) { */
- /* break; */
- /* } */
- }
- return 0;
-}
-
-/**
- * @brief Check for subbuffer ready to be read.
- *
- * @return 1 if there is subbuffer to be read, 0 - if there isn't.
- */
-int driver_to_buffer_buffer_to_read(void)
-{
- return busy_buffer ? 1 : 0;
-}
-
-/**
- * @brief Initializes SWAP buffer.
- *
- * @param size Size of one subbuffer.
- * @param count Count of subbuffers.
- * @return 0 on success, negative error code on error.
- */
-int driver_to_buffer_initialize(size_t size, unsigned int count)
-{
- int result;
- struct buffer_init_t buf_init = {
- .subbuffer_size = size,
- .nr_subbuffers = count,
- .subbuffer_full_cb = driver_to_buffer_callback,
- .lower_threshold = 20,
- .low_mem_cb = app_manage_pause_apps,
- .top_threshold = 80,
- .enough_mem_cb = app_manage_cont_apps,
- };
-
- if (size == 0 && count == 0)
- return -E_SD_WRONG_ARGS;
-
- result = swap_buffer_init(&buf_init);
- if (result == -E_SB_NO_MEM_QUEUE_BUSY
- || result == -E_SB_NO_MEM_BUFFER_STRUCT) {
- return -E_SD_NO_MEMORY;
- }
-
- /* TODO Race condition: buffer can be used in other thread till */
- /* we're in this func */
- /* Initialize driver_to_buffer variables */
- pages_per_buffer = result;
- busy_buffer = NULL;
- init_buffers_to_read();
-
- return E_SD_SUCCESS;
-}
-
-/**
- * @brief Uninitializes buffer.
- *
- * @return 0 on success, negative error code on error.
- */
-int driver_to_buffer_uninitialize(void)
-{
- int result;
-
- /* Release occupied buffer */
- if (busy_buffer) {
- result = driver_to_buffer_release();
- /* TODO Maybe release anyway */
- if (result < 0)
- return result;
- busy_buffer = NULL;
- }
-
- result = swap_buffer_uninit();
- if (result == -E_SB_UNRELEASED_BUFFERS) {
- print_err("Can't uninit buffer! There are busy subbuffers!\n");
- result = -E_SD_BUFFER_ERROR;
- } else if (result < 0) {
- print_err("swap_buffer_uninit error %d\n", result);
- result = -E_SD_BUFFER_ERROR;
- } else {
- result = E_SD_SUCCESS;
- }
-
- /* Reinit driver_to_buffer vars */
- init_buffers_to_read();
- pages_per_buffer = 0;
-
- return result;
-}
-
-/**
- * @brief Get next buffer to read.
- *
- * @return 0 on success, negative error code on error, E_SD_NO_DATA_TO_READ if
- * there is nothing to be read.
- */
-int driver_to_buffer_next_buffer_to_read(void)
-{
- int result;
-
- /* If there is busy_buffer first release it */
- if (busy_buffer) {
- result = driver_to_buffer_release();
- if (result)
- return result;
- }
-
- /* If there is no buffers to read, return E_SD_NO_DATA_TO_READ.
- * SHOULD BE POSITIVE, cause there is no real error. */
- if (!something_to_read())
- return E_SD_NO_DATA_TO_READ;
-
- /* Get next buffer to read */
- result = driver_to_buffer_get();
- if (result < 0) {
- print_err("buffer_to_reads > 0, but there are no buffers to read\n");
- return result;
- }
-
- /* Decrement buffers_to_read counter */
- dec_buffers_to_read();
-
- return E_SD_SUCCESS;
-}
+++ /dev/null
-/**
- * @file driver/driver_to_buffer.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Driver and buffer interaction interface declaration.
- */
-
-#ifndef __SWAP_DRIVER_DRIVER_TO_BUFFER__
-#define __SWAP_DRIVER_DRIVER_TO_BUFFER__
-
-int driver_to_buffer_initialize(size_t size, unsigned int count);
-int driver_to_buffer_uninitialize(void);
-ssize_t driver_to_buffer_read(char __user *buf, size_t count);
-int driver_to_buffer_fill_spd(struct splice_pipe_desc *spd);
-int driver_to_buffer_buffer_to_read(void);
-int driver_to_buffer_next_buffer_to_read(void);
-int driver_to_buffer_flush(void);
-
-
-#endif /* __SWAP_DRIVER_DRIVER_TO_BUFFER__ */
+++ /dev/null
-/**
- * @file driver/driver_to_msg.h
- * @author Vyacheslav Cherkashin
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Driver and parser interaction interface declaration.
- */
-
-#ifndef __SWAP_DRIVER_DRIVER_TO_MSG__
-#define __SWAP_DRIVER_DRIVER_TO_MSG__
-
-/** Defines type for message handler's pointer. */
-typedef int (*msg_handler_t)(void __user *data);
-
-/* Set the message handler */
-void set_msg_handler(msg_handler_t mh);
-
-#endif /* __SWAP_DRIVER_DRIVER_TO_MSG__ */
+++ /dev/null
-/**
- * @file driver/swap_driver_errors.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * SWAP driver error codes.
- */
-
-#ifndef __SWAP_DRIVER_ERRORS_H__
-#define __SWAP_DRIVER_ERRORS_H__
-
-
-/**
- * @enum _swap_driver_errors
- * @brief SWAP driver errors enumeration.
- */
-enum _swap_driver_errors {
- /**
- * @brief Success.
- */
- E_SD_SUCCESS = 0,
- /**
- * @brief Alloc_chrdev_region failed.
- */
- E_SD_ALLOC_CHRDEV_FAIL = 1,
- /**
- * @brief cdev_alloc failed.
- */
- E_SD_CDEV_ALLOC_FAIL = 2,
- /**
- * @brief cdev_add failed.
- */
- E_SD_CDEV_ADD_FAIL = 3,
- /**
- * @brief class_create failed.
- */
- E_SD_CLASS_CREATE_FAIL = 4,
- /**
- * @brief device_create failed.
- */
- E_SD_DEVICE_CREATE_FAIL = 5,
- /**
- * @brief splice_* funcs not found.
- */
- E_SD_NO_SPLICE_FUNCS = 6,
- /**
- * @brief swap_buffer_get tells us that there is no readable subbuffers.
- */
- E_SD_NO_DATA_TO_READ = 7,
- /**
- * @brief No busy subbuffer.
- */
- E_SD_NO_BUSY_SUBBUFFER = 8,
- /**
- * @brief Wrong subbuffer pointer passed to swap_buffer module.
- */
- E_SD_WRONG_SUBBUFFER_PTR = 9,
- /**
- * @brief Unhandled swap_buffer error.
- */
- E_SD_BUFFER_ERROR = 10,
- /**
- * @brief Write to subbuffer error.
- */
- E_SD_WRITE_ERROR = 11,
- /**
- * @brief Arguments, been passed to the func, doesn't pass sanity check.
- */
- E_SD_WRONG_ARGS = 12,
- /**
- * @brief No memory to allocate.
- */
- E_SD_NO_MEMORY = 13,
- /**
- * @brief swap_buffer uninitialization error.
- */
- E_SD_UNINIT_ERROR = 14,
- /**
- * @brief Netlink init error.
- */
- E_SD_NL_INIT_ERR = 15,
- /**
- * @brief Netlink message send error.
- */
- E_SD_NL_MSG_ERR = 16,
- /**
- * @brief No daemon pid in us_interaction.
- */
- E_SD_NO_DAEMON_PID = 17
-};
-
-#endif /* __SWAP_DRIVER_ERRORS_H__ */
+++ /dev/null
-/**
- * driver/swap_driver_module.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * SWAP drive module interface implementation.
- */
-
-#include <linux/module.h>
-#include <master/swap_initializer.h>
-#include "driver_defs.h"
-#include "device_driver.h"
-#include "us_interaction.h"
-
-static int fs_init(void)
-{
- int ret;
-
- ret = swap_device_init();
- if (ret)
- goto dev_init_fail;
-
- ret = us_interaction_create();
- if (ret)
- print_err("Cannot initialize netlink socket\n");
-
- print_msg("Driver module initialized\n");
-
- return 0;
-
-dev_init_fail:
- swap_device_exit();
-
- return ret;
-}
-
-static void fs_uninit(void)
-{
- us_interaction_destroy();
- swap_device_exit();
- print_msg("Driver module uninitialized\n");
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, NULL, NULL, fs_init, fs_uninit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP device driver");
-MODULE_AUTHOR("Aksenov A.S.");
+++ /dev/null
-/**
- * @file driver/swap_ioctl.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Provides ioctl commands and recources for SWAP driver.
- */
-
-#ifndef __SWAP_IOCTL_H__
-#define __SWAP_IOCTL_H__
-
-#include <linux/ioctl.h>
-
-/** SWAP device magic number. */
-#define SWAP_DRIVER_IOC_MAGIC 0xAF
-
-/**
- * @struct buffer_initialize
- * @brief SWAP buffer initialization struct.
- * @var buffer_initialize::size
- * Size of one subbuffer.
- * @var buffer_initialize::count
- * Count of subbuffers in the buffer.
- */
-struct buffer_initialize {
- size_t size;
- unsigned int count;
-};
-
-/* SWAP Device ioctl commands */
-
-/** Initialize buffer message. */
-#define SWAP_DRIVER_BUFFER_INITIALIZE _IOW(SWAP_DRIVER_IOC_MAGIC, 1, \
- struct buffer_initialize *)
-/** Uninitialize buffer message. */
-#define SWAP_DRIVER_BUFFER_UNINITIALIZE _IO(SWAP_DRIVER_IOC_MAGIC, 2)
-/** Set next buffer to read. */
-#define SWAP_DRIVER_NEXT_BUFFER_TO_READ _IO(SWAP_DRIVER_IOC_MAGIC, 3)
-/** Flush buffers. */
-#define SWAP_DRIVER_FLUSH_BUFFER _IO(SWAP_DRIVER_IOC_MAGIC, 4)
-/** Custom message. */
-#define SWAP_DRIVER_MSG _IOW(SWAP_DRIVER_IOC_MAGIC, 5, \
- void *)
-/** Force wake up daemon. */
-#define SWAP_DRIVER_WAKE_UP _IO(SWAP_DRIVER_IOC_MAGIC, 6)
-
-#endif /* __SWAP_IOCTL_H__ */
+++ /dev/null
-/**
- * driver/us_interaction.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * Kernel-to-user interface implementation.
- */
-
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/types.h>
-#include <linux/connector.h>
-#include <linux/slab.h>
-
-#include "us_interaction.h"
-#include "us_interaction_msg.h"
-#include "swap_driver_errors.h"
-#include "driver_defs.h"
-
-
-/* Connector id struct */
-static struct cb_id cn_swap_id = {CN_SWAP_IDX, CN_SWAP_VAL};
-
-/* Swap connector name */
-static const char cn_swap_name[] = "cn_swap";
-
-/* Send messages counter */
-static u32 msg_counter;
-
-/**
- * @brief Sends message to userspace via netlink.
- *
- * @param data Pointer to the data to be send.
- * @param size Size of the data to be send.
- * @return 0 on success, error code on error.
- */
-int us_interaction_send_msg(const void *data, size_t size)
-{
- struct cn_msg *msg;
- int ret;
-
- msg = kzalloc(sizeof(*msg) + size, GFP_ATOMIC);
- if (msg == NULL)
- return -E_SD_NO_MEMORY;
-
- memcpy(&msg->id, &cn_swap_id, sizeof(msg->id));
- msg->seq = msg_counter;
- msg->len = size;
- memcpy(msg->data, data, msg->len);
-
- ret = cn_netlink_send(msg, CN_DAEMON_GROUP, GFP_ATOMIC);
- if (ret < 0)
- goto fail_send;
- kfree(msg);
-
- msg_counter++;
-
- return E_SD_SUCCESS;
-
-fail_send:
- kfree(msg);
-
- return ret;
-}
-
-static void us_interaction_recv_msg(struct cn_msg *msg,
- struct netlink_skb_parms *nsp)
-{
-}
-
-/**
- * @brief Creates netlink connection.
- *
- * @return 0 on success, error code on error.
- */
-int us_interaction_create(void)
-{
- int res;
-
- res = cn_add_callback(&cn_swap_id,
- cn_swap_name,
- us_interaction_recv_msg);
- if (res)
- return -E_SD_NL_INIT_ERR;
-
- return E_SD_SUCCESS;
-}
-
-/**
- * @brief Destroy netlink connection.
- *
- * @return Void.
- */
-void us_interaction_destroy(void)
-{
- cn_del_callback(&cn_swap_id);
-}
+++ /dev/null
-/**
- * @file driver/us_interaction.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * Kernel-to-user interface definition.
- */
-
-#ifndef __US_INTERACTION_H__
-#define __US_INTERACTION_H__
-
-#ifdef CONFIG_CONNECTOR
-
-int us_interaction_create(void);
-void us_interaction_destroy(void);
-int us_interaction_send_msg(const void *data, size_t size);
-
-#else /* CONFIG_CONNECTOR */
-
-static inline int us_interaction_create(void)
-{
- return -EPERM;
-}
-
-static inline void us_interaction_destroy(void)
-{
-}
-
-static inline int us_interaction_send_msg(const void *data, size_t size)
-{
- return -EPERM;
-}
-
-#endif /* CONFIG_CONNECTOR */
-
-#endif /* __US_INTERACTION_H__ */
+++ /dev/null
-/**
- * @file driver/us_interaction_msg.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * Netlink messages declaration.
- */
-
-#ifndef __US_INTERACTION_MSG_H__
-#define __US_INTERACTION_MSG_H__
-
-#define CN_SWAP_IDX 0x22 /**< Should be unique throughout the system */
-#define CN_SWAP_VAL 0x1 /**< Just the same in kernel and user */
-#define CN_DAEMON_GROUP 0x1 /**< Listener group. Connector works a bit
- * faster when using one */
-
-/**
- * @enum us_interaction_k2u_msg_t
- * @brief Kernel-to-user netlink messages headers.
- */
-enum us_interaction_k2u_msg_t {
- /**
- * @brief Make daemon pause apps.
- */
- US_INT_PAUSE_APPS = 1,
- /**
- * @brief Make daemon continue apps.
- */
- US_INT_CONT_APPS = 2
-};
-
-#endif /* __US_INTERACTION_MSG_H__ */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-
-
-
-
-###############################################################################
-### swap energy module description ###
-###############################################################################
-obj-$(CONFIG_SWAP_DA) := swap_energy.o
-swap_energy-y := energy_module.o \
- energy.o \
- rational_debugfs.o \
- debugfs_energy.o \
- lcd/lcd_base.o \
- lcd/lcd_debugfs.o
-
-
-
-
-
-###############################################################################
-### math support ###
-###############################################################################
-# S6E8AA0:
-ifeq ($(CONFIG_LCD_S6E8AA0), y)
- swap_energy-y += lcd/s6e8aa0.o
- LCD_FUNC_LIST += s6e8aa0
-endif
-
-
-# PANEL_S6E8AA0:
-ifeq ($(CONFIG_DISPLAY_PANEL_S6E8AA0), y)
- swap_energy-y += lcd/s6e8aa0_panel.o
- LCD_FUNC_LIST += s6e8aa0_panel
-endif
-
-
-# MARU:
-ifeq ($(CONFIG_MARU_BACKLIGHT), y)
- swap_energy-y += lcd/maru.o
- LCD_FUNC_LIST += maru
-endif
-
-
-
-
-
-###############################################################################
-### description functions ###
-###############################################################################
-LCD_FUNC_ARGS := void
-LCD_FUNC_RET := struct lcd_ops *
-
-
-
-
-
-###############################################################################
-### generate defines ###
-###############################################################################
-LCD_PREFIX := lcd_energy_
-
-# add prefix
-TMP := $(foreach it, $(LCD_FUNC_LIST), $(LCD_PREFIX)$(it))
-LCD_FUNC_LIST := $(TMP)
-
-# generate DEFINITION_LCD_FUNC
-TMP := ($(LCD_FUNC_ARGS));
-DEFINITION_LCD_FUNC := DEFINITION_LCD_FUNC=\
-$(foreach it, $(LCD_FUNC_LIST), "extern" $(LCD_FUNC_RET) $(it)$(TMP))
-
-
-# generate DEFINITION_LCD_ARRAY
-COMMA := ,
-AND := &
-DEFINITION_LCD_ARRAY := DEFINITION_LCD_ARRAY=\
-"{" $(foreach it, $(LCD_FUNC_LIST), &$(it),) "}"
-
-
-# generate LCD_MAKE_FNAME
-LCD_MAKE_FNAME := LCD_MAKE_FNAME(name)=$(LCD_PREFIX)\#\#name
-
-
-
-
-
-###############################################################################
-### add generate defines to EXTRA_CFLAGS ###
-###############################################################################
-ccflags-y += -D"$(DEFINITION_LCD_FUNC)" \
- -D"$(DEFINITION_LCD_ARRAY)" \
- -D"$(LCD_MAKE_FNAME)"
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * energy/debugfs_energy.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/math64.h>
-#include <master/swap_debugfs.h>
-#include "energy.h"
-#include "debugfs_energy.h"
-#include "rational_debugfs.h"
-#include "lcd/lcd_debugfs.h"
-#include "lcd/lcd_base.h"
-
-
-/* CPU running */
-static DEFINE_RATIONAL(cpu0_running_coef); /* boot core uses distinct coeff */
-static DEFINE_RATIONAL(cpuN_running_coef);
-
-static u64 __energy_cpu(enum parameter_energy pe)
-{
- u64 times[NR_CPUS] = { 0 };
- u64 val = 0;
- int i;
-
- if (get_parameter_energy(pe, times, sizeof(times)) == 0) {
- val = div_u64(times[0] * cpu0_running_coef.num,
- cpu0_running_coef.denom);
- for (i = 1; i < NR_CPUS; i++)
- val += div_u64(times[i] * cpuN_running_coef.num,
- cpuN_running_coef.denom);
- }
-
- return val;
-}
-
-static u64 cpu_system(void)
-{
- return __energy_cpu(PE_TIME_SYSTEM);
-}
-
-static u64 cpu_apps(void)
-{
- return __energy_cpu(PE_TIME_APPS);
-}
-
-
-/* CPU idle */
-static DEFINE_RATIONAL(cpu_idle_coef);
-
-static u64 cpu_idle_system(void)
-{
- u64 time = 0;
-
- get_parameter_energy(PE_TIME_IDLE, &time, sizeof(time));
- return div_u64(time * cpu_idle_coef.num, cpu_idle_coef.denom);
-}
-
-
-/* flash read */
-static DEFINE_RATIONAL(fr_coef);
-
-static u64 fr_system(void)
-{
- u64 byte = 0;
-
- get_parameter_energy(PE_READ_SYSTEM, &byte, sizeof(byte));
- return div_u64(byte * fr_coef.num, fr_coef.denom);
-}
-
-static u64 fr_apps(void)
-{
- u64 byte = 0;
-
- get_parameter_energy(PE_READ_APPS, &byte, sizeof(byte));
- return div_u64(byte * fr_coef.num, fr_coef.denom);
-}
-
-
-/* flash write */
-static DEFINE_RATIONAL(fw_coef);
-
-static u64 fw_system(void)
-{
- u64 byte = 0;
-
- get_parameter_energy(PE_WRITE_SYSTEM, &byte, sizeof(byte));
- return div_u64(byte * fw_coef.num, fw_coef.denom);
-}
-
-static u64 fw_apps(void)
-{
- u64 byte = 0;
-
- get_parameter_energy(PE_WRITE_APPS, &byte, sizeof(byte));
- return div_u64(byte * fw_coef.num, fw_coef.denom);
-}
-
-
-
-
-
-/* ============================================================================
- * === PARAMETERS ===
- * ============================================================================
- */
-static int get_func_u64(void *data, u64 *val)
-{
- u64 (*func)(void) = data;
- *val = func();
- return 0;
-}
-
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_get_u64, get_func_u64, NULL, "%llu\n");
-
-
-struct param_data {
- char *name;
- struct rational *coef;
- u64 (*system)(void);
- u64 (*apps)(void);
-};
-
-static struct dentry *create_parameter(struct dentry *parent,
- struct param_data *param)
-{
- struct dentry *name, *system, *apps = NULL;
-
- name = debugfs_create_dir(param->name, parent);
- if (name == NULL)
- return NULL;
-
- system = debugfs_create_file("system", 0600, name, param->system,
- &fops_get_u64);
- if (system == NULL)
- goto rm_name;
-
- if (param->apps) {
- apps = debugfs_create_file("apps", 0600, name, param->apps,
- &fops_get_u64);
- if (apps == NULL)
- goto rm_system;
- }
-
- if (create_rational_files(name, param->coef,
- "numerator", "denominator"))
- goto rm_apps;
-
- return name;
-
-rm_apps:
- if (param->apps)
- debugfs_remove(apps);
-rm_system:
- debugfs_remove(system);
-rm_name:
- debugfs_remove(name);
-
- return NULL;
-}
-
-struct param_data parameters[] = {
- {
- .name = "cpu_running",
- .coef = &cpu0_running_coef,
- .system = cpu_system,
- .apps = cpu_apps
- },
- {
- .name = "cpuN_running",
- .coef = &cpuN_running_coef,
- .system = cpu_system,
- .apps = cpu_apps
- },
- {
- .name = "cpu_idle",
- .coef = &cpu_idle_coef,
- .system = cpu_idle_system,
- .apps = NULL
- },
- {
- .name = "flash_read",
- .coef = &fr_coef,
- .system = fr_system,
- .apps = fr_apps
- },
- {
- .name = "flash_write",
- .coef = &fw_coef,
- .system = fw_system,
- .apps = fw_apps
- }
-};
-
-enum {
- parameters_cnt = sizeof(parameters) / sizeof(struct param_data)
-};
-
-
-
-
-
-/* ============================================================================
- * === INIT/EXIT ===
- * ============================================================================
- */
-static struct dentry *energy_dir;
-
-/**
- * @brief Destroy debugfs for LCD
- *
- * @return Dentry of energy debugfs
- */
-struct dentry *get_energy_dir(void)
-{
- return energy_dir;
-}
-
-/**
- * @brief Destroy debugfs for energy
- *
- * @return Void
- */
-void exit_debugfs_energy(void)
-{
- lcd_exit();
- exit_lcd_debugfs();
-
- if (energy_dir)
- debugfs_remove_recursive(energy_dir);
-
- energy_dir = NULL;
-}
-
-/**
- * @brief Create debugfs for energy
- *
- * @return Error code
- */
-int init_debugfs_energy(void)
-{
- int i;
- struct dentry *swap_dir, *dentry;
-
- swap_dir = swap_debugfs_getdir();
- if (swap_dir == NULL)
- return -ENOENT;
-
- energy_dir = debugfs_create_dir("energy", swap_dir);
- if (energy_dir == NULL)
- return -ENOMEM;
-
- for (i = 0; i < parameters_cnt; ++i) {
- dentry = create_parameter(energy_dir, ¶meters[i]);
- if (dentry == NULL)
- goto fail;
- }
-
- if (init_lcd_debugfs(energy_dir))
- goto fail;
-
- /* Actually, the only goal of lcd_init() is to register lcd screen's
- debugfs, so it is called here. */
- if (lcd_init()) {
- exit_lcd_debugfs();
- }
-
- return 0;
-
-fail:
- exit_debugfs_energy();
- return -ENOMEM;
-}
+++ /dev/null
-#ifndef _DEBUGFS_ENERGY_H
-#define _DEBUGFS_ENERGY_H
-
-/**
- * @file energy/debugfs_energy.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- * Debugfs for energy
- */
-
-
-#include <linux/fs.h>
-#include <master/swap_initializer.h>
-
-
-struct dentry;
-
-
-/* based on define DEFINE_SIMPLE_ATTRIBUTE */
-#define SWAP_DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \
-static int __fops ## _open(struct inode *inode, struct file *file) \
-{ \
- int ret; \
- \
- ret = swap_init_simple_open(inode, file); \
- if (ret) \
- return ret; \
- \
- __simple_attr_check_format(__fmt, 0ull); \
- ret = simple_attr_open(inode, file, __get, __set, __fmt); \
- if (ret) \
- swap_init_simple_release(inode, file); \
- \
- return ret; \
-} \
-static int __fops ## _release(struct inode *inode, struct file *file) \
-{ \
- simple_attr_release(inode, file); \
- swap_init_simple_release(inode, file); \
- \
- return 0; \
-} \
-static const struct file_operations __fops = { \
- .owner = THIS_MODULE, \
- .open = __fops ## _open, \
- .release = __fops ## _release, \
- .read = simple_attr_read, \
- .write = simple_attr_write, \
- .llseek = generic_file_llseek, \
-}
-
-
-int init_debugfs_energy(void);
-void exit_debugfs_energy(void);
-
-struct dentry *get_energy_dir(void);
-
-
-#endif /* _DEBUGFS_ENERGY_H */
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * modules/energy/swap_energy.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vasiliy Ulyanov <v.ulyanov@samsung.com>
- * Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/file.h>
-#include <linux/spinlock.h>
-#include <linux/magic.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <kprobe/swap_kprobes.h>
-#include <ksyms/ksyms.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/sspt/sspt_feature.h>
-#include <linux/atomic.h>
-#include "energy.h"
-#include "lcd/lcd_base.h"
-#include "tm_stat.h"
-
-
-/* ============================================================================
- * = CPUS_TIME =
- * ============================================================================
- */
-struct cpus_time {
- spinlock_t lock; /* for concurrent access */
- struct tm_stat tm[NR_CPUS];
-};
-
-#define cpus_time_lock(ct, flags) spin_lock_irqsave(&(ct)->lock, flags)
-#define cpus_time_unlock(ct, flags) spin_unlock_irqrestore(&(ct)->lock, flags)
-
-static void cpus_time_init(struct cpus_time *ct, u64 time)
-{
- int cpu;
-
- spin_lock_init(&ct->lock);
-
- for (cpu = 0; cpu < NR_CPUS; ++cpu) {
- tm_stat_init(&ct->tm[cpu]);
- tm_stat_set_timestamp(&ct->tm[cpu], time);
- }
-}
-
-static inline u64 cpu_time_get_running(struct cpus_time *ct, int cpu, u64 now)
-{
- return tm_stat_current_running(&ct->tm[cpu], now);
-}
-
-static void *cpus_time_get_running_all(struct cpus_time *ct, u64 *buf, u64 now)
-{
- int cpu;
-
- for (cpu = 0; cpu < NR_CPUS; ++cpu)
- buf[cpu] = tm_stat_current_running(&ct->tm[cpu], now);
-
- return buf;
-}
-
-static void *cpus_time_sum_running_all(struct cpus_time *ct, u64 *buf, u64 now)
-{
- int cpu;
-
- for (cpu = 0; cpu < NR_CPUS; ++cpu)
- buf[cpu] += tm_stat_current_running(&ct->tm[cpu], now);
-
- return buf;
-}
-
-static void cpus_time_save_entry(struct cpus_time *ct, int cpu, u64 time)
-{
- struct tm_stat *tm = &ct->tm[cpu];
-
- if (unlikely(tm_stat_timestamp(tm))) /* should never happen */
- printk(KERN_INFO "XXX %s[%d/%d]: WARNING tmstamp(%p) set on cpu(%d)\n",
- current->comm, current->tgid, current->pid, tm, cpu);
- tm_stat_set_timestamp(&ct->tm[cpu], time);
-}
-
-static void cpus_time_update_running(struct cpus_time *ct, int cpu, u64 now,
- u64 start_time)
-{
- struct tm_stat *tm = &ct->tm[cpu];
-
- if (unlikely(tm_stat_timestamp(tm) == 0)) {
- /* not initialized. should happen only once per cpu/task */
- printk(KERN_INFO "XXX %s[%d/%d]: nnitializing tmstamp(%p) "
- "on cpu(%d)\n",
- current->comm, current->tgid, current->pid, tm, cpu);
- tm_stat_set_timestamp(tm, start_time);
- }
-
- tm_stat_update(tm, now);
- tm_stat_set_timestamp(tm, 0); /* set timestamp to 0 */
-}
-
-
-
-
-
-struct energy_data {
- /* for __switch_to */
- struct cpus_time ct;
-
- /* for sys_read */
- atomic64_t bytes_read;
-
- /*for sys_write */
- atomic64_t bytes_written;
-
-};
-
-static sspt_feature_id_t feature_id = SSPT_FEATURE_ID_BAD;
-
-static void init_ed(struct energy_data *ed)
-{
- /* instead of get_ntime(), CPU time is initialized to 0 here. Timestamp
- * value will be properly set when the corresponding __switch_to event
- * occurs */
- cpus_time_init(&ed->ct, 0);
- atomic64_set(&ed->bytes_read, 0);
- atomic64_set(&ed->bytes_written, 0);
-}
-
-static void uninit_ed(struct energy_data *ed)
-{
- cpus_time_init(&ed->ct, 0);
- atomic64_set(&ed->bytes_read, 0);
- atomic64_set(&ed->bytes_written, 0);
-}
-
-static void *create_ed(void)
-{
- struct energy_data *ed;
-
- ed = kmalloc(sizeof(*ed), GFP_ATOMIC);
- if (ed)
- init_ed(ed);
-
- return (void *)ed;
-}
-
-static void destroy_ed(void *data)
-{
- struct energy_data *ed = (struct energy_data *)data;
- kfree(ed);
-}
-
-
-static int init_feature(void)
-{
- feature_id = sspt_register_feature(create_ed, destroy_ed);
-
- if (feature_id == SSPT_FEATURE_ID_BAD)
- return -EPERM;
-
- return 0;
-}
-
-static void uninit_feature(void)
-{
- sspt_unregister_feature(feature_id);
- feature_id = SSPT_FEATURE_ID_BAD;
-}
-
-static struct energy_data *get_energy_data(struct task_struct *task)
-{
- void *data = NULL;
- struct sspt_proc *proc;
-
- proc = sspt_proc_get_by_task(task);
- if (proc)
- data = sspt_get_feature_data(proc->feature, feature_id);
-
- return (struct energy_data *)data;
-}
-
-static int check_fs(unsigned long magic)
-{
- switch (magic) {
- case EXT2_SUPER_MAGIC: /* == EXT3_SUPER_MAGIC == EXT4_SUPER_MAGIC */
- case MSDOS_SUPER_MAGIC:
- return 1;
- }
-
- return 0;
-}
-
-static int check_ftype(int fd)
-{
- int err, ret = 0;
- struct kstat kstat;
-
- err = vfs_fstat(fd, &kstat);
- if (err == 0 && S_ISREG(kstat.mode))
- ret = 1;
-
- return ret;
-}
-
-static int check_file(int fd)
-{
- struct file *file;
-
- file = fget(fd);
- if (file) {
- int magic = 0;
- if (file->f_dentry && file->f_dentry->d_sb)
- magic = file->f_dentry->d_sb->s_magic;
-
- fput(file);
-
- if (check_fs(magic) && check_ftype(fd))
- return 1;
- }
-
- return 0;
-}
-
-static unsigned long get_arg0(struct pt_regs *regs)
-{
-#if defined(CONFIG_ARM)
- return regs->ARM_r0;
-#elif defined(CONFIG_X86_32)
- return regs->bx;
-#else
- #error "this architecture is not supported"
-#endif /* CONFIG_arch */
-}
-
-
-
-
-
-static struct cpus_time ct_idle;
-static struct energy_data ed_system;
-static u64 start_time;
-
-static void init_data_energy(void)
-{
- start_time = get_ntime();
- init_ed(&ed_system);
- cpus_time_init(&ct_idle, 0);
-}
-
-static void uninit_data_energy(void)
-{
- start_time = 0;
- uninit_ed(&ed_system);
- cpus_time_init(&ct_idle, 0);
-}
-
-
-
-
-
-/* ============================================================================
- * = __switch_to =
- * ============================================================================
- */
-static int entry_handler_switch(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int cpu;
- struct cpus_time *ct;
- struct energy_data *ed;
- unsigned long flags;
-
- cpu = smp_processor_id();
-
- ct = current->tgid ? &ed_system.ct : &ct_idle;
- cpus_time_lock(ct, flags);
- cpus_time_update_running(ct, cpu, get_ntime(), start_time);
- cpus_time_unlock(ct, flags);
-
- ed = get_energy_data(current);
- if (ed) {
- ct = &ed->ct;
- cpus_time_lock(ct, flags);
- cpus_time_update_running(ct, cpu, get_ntime(), start_time);
- cpus_time_unlock(ct, flags);
- }
-
- return 0;
-}
-
-static int ret_handler_switch(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int cpu;
- struct cpus_time *ct;
- struct energy_data *ed;
- unsigned long flags;
-
- cpu = smp_processor_id();
-
- ct = current->tgid ? &ed_system.ct : &ct_idle;
- cpus_time_lock(ct, flags);
- cpus_time_save_entry(ct, cpu, get_ntime());
- cpus_time_unlock(ct, flags);
-
- ed = get_energy_data(current);
- if (ed) {
- ct = &ed->ct;
- cpus_time_lock(ct, flags);
- cpus_time_save_entry(ct, cpu, get_ntime());
- cpus_time_unlock(ct, flags);
- }
-
- return 0;
-}
-
-static struct kretprobe switch_to_krp = {
- .entry_handler = entry_handler_switch,
- .handler = ret_handler_switch,
-};
-
-
-
-
-
-/* ============================================================================
- * = sys_read =
- * ============================================================================
- */
-struct sys_read_data {
- int fd;
-};
-
-static int entry_handler_sys_read(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct sys_read_data *srd = (struct sys_read_data *)ri->data;
-
- srd->fd = (int)get_arg0(regs);
-
- return 0;
-}
-
-static int ret_handler_sys_read(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int ret = regs_return_value(regs);
-
- if (ret > 0) {
- struct sys_read_data *srd;
-
- srd = (struct sys_read_data *)ri->data;
- if (check_file(srd->fd)) {
- struct energy_data *ed;
-
- ed = get_energy_data(current);
- if (ed)
- atomic64_add(ret, &ed->bytes_read);
-
- atomic64_add(ret, &ed_system.bytes_read);
- }
- }
-
- return 0;
-}
-
-static struct kretprobe sys_read_krp = {
- .entry_handler = entry_handler_sys_read,
- .handler = ret_handler_sys_read,
- .data_size = sizeof(struct sys_read_data)
-};
-
-
-
-
-
-/* ============================================================================
- * = sys_write =
- * ============================================================================
- */
-static int entry_handler_sys_write(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct sys_read_data *srd = (struct sys_read_data *)ri->data;
-
- srd->fd = (int)get_arg0(regs);
-
- return 0;
-}
-
-static int ret_handler_sys_write(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int ret = regs_return_value(regs);
-
- if (ret > 0) {
- struct sys_read_data *srd;
-
- srd = (struct sys_read_data *)ri->data;
- if (check_file(srd->fd)) {
- struct energy_data *ed;
-
- ed = get_energy_data(current);
- if (ed)
- atomic64_add(ret, &ed->bytes_written);
-
- atomic64_add(ret, &ed_system.bytes_written);
- }
- }
-
- return 0;
-}
-
-static struct kretprobe sys_write_krp = {
- .entry_handler = entry_handler_sys_write,
- .handler = ret_handler_sys_write,
- .data_size = sizeof(struct sys_read_data)
-};
-
-
-
-
-
-enum parameter_type {
- PT_CPU,
- PT_READ,
- PT_WRITE
-};
-
-struct cmd_pt {
- enum parameter_type pt;
- void *buf;
- int sz;
-};
-
-static void callback_for_proc(struct sspt_proc *proc, void *data)
-{
- void *f_data = sspt_get_feature_data(proc->feature, feature_id);
- struct energy_data *ed = (struct energy_data *)f_data;
-
- if (ed) {
- unsigned long flags;
- struct cmd_pt *cmdp = (struct cmd_pt *)data;
- u64 *val = cmdp->buf;
-
- switch (cmdp->pt) {
- case PT_CPU:
- cpus_time_lock(&ed->ct, flags);
- cpus_time_sum_running_all(&ed->ct, val, get_ntime());
- cpus_time_unlock(&ed->ct, flags);
- break;
- case PT_READ:
- *val += atomic64_read(&ed->bytes_read);
- break;
- case PT_WRITE:
- *val += atomic64_read(&ed->bytes_written);
- break;
- default:
- break;
- }
- }
-}
-
-static int current_parameter_apps(enum parameter_type pt, void *buf, int sz)
-{
- struct cmd_pt cmdp;
-
- cmdp.pt = pt;
- cmdp.buf = buf;
- cmdp.sz = sz;
-
- on_each_proc(callback_for_proc, (void *)&cmdp);
-
- return 0;
-}
-
-/**
- * @brief Get energy parameter
- *
- * @param pe Type of energy parameter
- * @param buf Buffer
- * @param sz Buffer size
- * @return Error code
- */
-int get_parameter_energy(enum parameter_energy pe, void *buf, size_t sz)
-{
- unsigned long flags;
- u64 *val = buf; /* currently all parameters are u64 vals */
- int ret = 0;
-
- switch (pe) {
- case PE_TIME_IDLE:
- cpus_time_lock(&ct_idle, flags);
- /* for the moment we consider only CPU[0] idle time */
- *val = cpu_time_get_running(&ct_idle, 0, get_ntime());
- cpus_time_unlock(&ct_idle, flags);
- break;
- case PE_TIME_SYSTEM:
- cpus_time_lock(&ed_system.ct, flags);
- cpus_time_get_running_all(&ed_system.ct, val, get_ntime());
- cpus_time_unlock(&ed_system.ct, flags);
- break;
- case PE_TIME_APPS:
- current_parameter_apps(PT_CPU, buf, sz);
- break;
- case PE_READ_SYSTEM:
- *val = atomic64_read(&ed_system.bytes_read);
- break;
- case PE_WRITE_SYSTEM:
- *val = atomic64_read(&ed_system.bytes_written);
- break;
- case PE_READ_APPS:
- current_parameter_apps(PT_READ, buf, sz);
- break;
- case PE_WRITE_APPS:
- current_parameter_apps(PT_WRITE, buf, sz);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-int do_set_energy(void)
-{
- int ret = 0;
-
- init_data_energy();
-
- ret = swap_register_kretprobe(&sys_read_krp);
- if (ret) {
- printk(KERN_INFO "swap_register_kretprobe(sys_read) "
- "result=%d!\n", ret);
- return ret;
- }
-
- ret = swap_register_kretprobe(&sys_write_krp);
- if (ret != 0) {
- printk(KERN_INFO "swap_register_kretprobe(sys_write) "
- "result=%d!\n", ret);
- goto unregister_sys_read;
- }
-
- ret = swap_register_kretprobe(&switch_to_krp);
- if (ret) {
- printk(KERN_INFO "swap_register_kretprobe(__switch_to) "
- "result=%d!\n",
- ret);
- goto unregister_sys_write;
- }
-
- /* TODO: check return value */
- lcd_set_energy();
-
- return ret;
-
-unregister_sys_read:
- swap_unregister_kretprobe(&sys_read_krp);
-
-unregister_sys_write:
- swap_unregister_kretprobe(&sys_write_krp);
-
- return ret;
-}
-
-void do_unset_energy(void)
-{
- lcd_unset_energy();
-
- swap_unregister_kretprobe(&switch_to_krp);
- swap_unregister_kretprobe(&sys_write_krp);
- swap_unregister_kretprobe(&sys_read_krp);
-
- uninit_data_energy();
-}
-
-static DEFINE_MUTEX(mutex_enable);
-static int energy_enable;
-
-/**
- * @brief Start measuring the energy consumption
- *
- * @return Error code
- */
-int set_energy(void)
-{
- int ret = -EINVAL;
-
- mutex_lock(&mutex_enable);
- if (energy_enable) {
- printk(KERN_INFO "energy profiling is already run!\n");
- goto unlock;
- }
-
- ret = do_set_energy();
- if (ret == 0)
- energy_enable = 1;
-
-unlock:
- mutex_unlock(&mutex_enable);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(set_energy);
-
-/**
- * @brief Stop measuring the energy consumption
- *
- * @return Error code
- */
-int unset_energy(void)
-{
- int ret = 0;
-
- mutex_lock(&mutex_enable);
- if (energy_enable == 0) {
- printk(KERN_INFO "energy profiling is not running!\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- do_unset_energy();
-
- energy_enable = 0;
-unlock:
- mutex_unlock(&mutex_enable);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(unset_energy);
-
-int energy_once(void)
-{
- const char *sym;
-
- sym = "__switch_to";
- switch_to_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
- if (switch_to_krp.kp.addr == NULL)
- goto not_found;
-
- sym = "sys_read";
- sys_read_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
- if (sys_read_krp.kp.addr == NULL)
- goto not_found;
-
- sym = "sys_write";
- sys_write_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
- if (sys_write_krp.kp.addr == NULL)
- goto not_found;
-
- return 0;
-
-not_found:
- printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
- return -ESRCH;
-}
-
-/**
- * @brief Initialization energy
- *
- * @return Error code
- */
-int energy_init(void)
-{
- int ret;
-
- ret = init_feature();
- if (ret)
- printk(KERN_INFO "Cannot init feature\n");
-
- return ret;
-}
-
-/**
- * @brief Deinitialization energy
- *
- * @return Void
- */
-void energy_uninit(void)
-{
- uninit_feature();
-
- if (energy_enable)
- do_unset_energy();
-}
+++ /dev/null
-#ifndef _ENERGY_H
-#define _ENERGY_H
-
-/**
- * @file energy/energy.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENCE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- */
-
-
-#include <linux/types.h>
-
-
-/** Description of parameters */
-enum parameter_energy {
- PE_TIME_IDLE, /**< IDLE working time */
- PE_TIME_SYSTEM, /**< system working time */
- PE_TIME_APPS, /**< apps working time */
- PE_READ_SYSTEM, /**< number of bytes are read by system */
- PE_WRITE_SYSTEM, /**< number of bytes are write by system */
- PE_READ_APPS, /**< number of bytes are read by apps */
- PE_WRITE_APPS /**< number of bytes are write by apps*/
-};
-
-
-int energy_once(void);
-int energy_init(void);
-void energy_uninit(void);
-
-int set_energy(void);
-int unset_energy(void);
-
-int get_parameter_energy(enum parameter_energy pe, void *buf, size_t sz);
-
-#endif /* _ENERGY_H */
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * energy/energy_mod.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <master/swap_initializer.h>
-#include "energy.h"
-#include "debugfs_energy.h"
-
-
-SWAP_LIGHT_INIT_MODULE(energy_once, energy_init, energy_uninit,
- init_debugfs_energy, exit_debugfs_energy);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * energy/lcd/lcd_base.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/fb.h>
-#include <energy/tm_stat.h>
-#include <energy/debugfs_energy.h>
-#include "lcd_base.h"
-#include "lcd_debugfs.h"
-
-
-/**
- * @brief Read the number of file
- *
- * @param path of the file
- * @return Value or error(when negative)
- */
-int read_val(const char *path)
-{
- int ret;
- struct file *f;
- unsigned long val;
- enum { buf_len = 32 };
- char buf[buf_len];
-
- f = filp_open(path, O_RDONLY, 0);
- if (IS_ERR(f)) {
- printk(KERN_INFO "cannot open file \'%s\'", path);
- return PTR_ERR(f);
- }
-
- ret = kernel_read(f, 0, buf, sizeof(buf));
- filp_close(f, NULL);
- if (ret < 0)
- return ret;
-
- buf[ret >= buf_len ? buf_len - 1 : ret] = '\0';
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret)
- return ret;
-
- return (int)val;
-}
-
-enum {
- brt_no_init = -1,
- brt_cnt = 10
-};
-
-enum power_t {
- PW_ON,
- PW_OFF
-};
-
-struct lcd_priv_data {
- int min_brt;
- int max_brt;
-
- size_t tms_brt_cnt;
- struct tm_stat *tms_brt;
- spinlock_t lock_tms;
- int brt_old;
- enum power_t power;
-
- u64 min_denom;
- u64 min_num;
- u64 max_denom;
- u64 max_num;
-};
-
-static void *create_lcd_priv(struct lcd_ops *ops, size_t tms_brt_cnt)
-{
- int i;
- struct lcd_priv_data *lcd;
-
- if (tms_brt_cnt <= 0) {
- printk(KERN_INFO "error variable tms_brt_cnt=%d\n",
- tms_brt_cnt);
- return NULL;
- }
-
- lcd = kmalloc(sizeof(*lcd) + sizeof(*lcd->tms_brt) * tms_brt_cnt,
- GFP_KERNEL);
- if (lcd == NULL) {
- printk(KERN_INFO "error: %s - out of memory\n", __func__);
- return NULL;
- }
-
- lcd->tms_brt = (void *)lcd + sizeof(*lcd);
- lcd->tms_brt_cnt = tms_brt_cnt;
-
- lcd->min_brt = ops->get(ops, LPD_MIN_BRIGHTNESS);
- lcd->max_brt = ops->get(ops, LPD_MAX_BRIGHTNESS);
-
- for (i = 0; i < tms_brt_cnt; ++i)
- tm_stat_init(&lcd->tms_brt[i]);
-
- spin_lock_init(&lcd->lock_tms);
-
- lcd->brt_old = brt_no_init;
- lcd->power = PW_OFF;
-
- lcd->min_denom = 1;
- lcd->min_num = 1;
- lcd->max_denom = 1;
- lcd->max_num = 1;
-
- return (void *)lcd;
-}
-
-static void destroy_lcd_priv(void *data)
-{
- kfree(data);
-}
-
-static struct lcd_priv_data *get_lcd_priv(struct lcd_ops *ops)
-{
- return (struct lcd_priv_data *)ops->priv;
-}
-
-static void clean_brightness(struct lcd_ops *ops)
-{
- struct lcd_priv_data *lcd = get_lcd_priv(ops);
- int i;
-
- spin_lock(&lcd->lock_tms);
- for (i = 0; i < lcd->tms_brt_cnt; ++i)
- tm_stat_init(&lcd->tms_brt[i]);
-
- lcd->brt_old = brt_no_init;
- spin_unlock(&lcd->lock_tms);
-}
-
-static int get_brt_num_of_array(struct lcd_priv_data *lcd, int brt)
-{
- if (brt > lcd->max_brt || brt < lcd->min_brt) {
- printk(KERN_INFO "LCD energy error: set brightness=%d, "
- "when brightness[%d..%d]\n",
- brt, lcd->min_brt, lcd->max_brt);
- brt = brt > lcd->max_brt ? lcd->max_brt : lcd->min_brt;
- }
-
- return lcd->tms_brt_cnt * (brt - lcd->min_brt) /
- (lcd->max_brt - lcd->min_brt + 1);
-}
-
-static void set_brightness(struct lcd_ops *ops, int brt)
-{
- struct lcd_priv_data *lcd = get_lcd_priv(ops);
- int n = get_brt_num_of_array(lcd, brt);
-
- spin_lock(&lcd->lock_tms);
-
- if (lcd->power == PW_ON && lcd->brt_old != n) {
- u64 time = get_ntime();
- if (lcd->brt_old != brt_no_init)
- tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
-
- tm_stat_set_timestamp(&lcd->tms_brt[n], time);
- }
- lcd->brt_old = n;
-
- spin_unlock(&lcd->lock_tms);
-}
-
-static void set_power_on_set_brt(struct lcd_priv_data *lcd)
-{
- if (lcd->brt_old != brt_no_init) {
- u64 time = get_ntime();
- tm_stat_set_timestamp(&lcd->tms_brt[lcd->brt_old], time);
- }
-}
-
-static void set_power_on(struct lcd_priv_data *lcd)
-{
- if (lcd->power == PW_OFF)
- set_power_on_set_brt(lcd);
-
- lcd->power = PW_ON;
-}
-
-static void set_power_off_update_brt(struct lcd_priv_data *lcd)
-{
- if (lcd->brt_old != brt_no_init) {
- u64 time = get_ntime();
- tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
- lcd->brt_old = brt_no_init;
- }
-}
-
-static void set_power_off(struct lcd_priv_data *lcd)
-{
- if (lcd->power == PW_ON)
- set_power_off_update_brt(lcd);
-
- lcd->power = PW_OFF;
-}
-
-static void set_power(struct lcd_ops *ops, int val)
-{
- struct lcd_priv_data *lcd = get_lcd_priv(ops);
-
- spin_lock(&lcd->lock_tms);
-
- switch (val) {
- case FB_BLANK_UNBLANK:
- set_power_on(lcd);
- break;
- case FB_BLANK_POWERDOWN:
- set_power_off(lcd);
- break;
- default:
- printk(KERN_INFO "LCD energy error: set power=%d\n", val);
- break;
- }
-
- spin_unlock(&lcd->lock_tms);
-}
-
-static int func_notifier_lcd(struct lcd_ops *ops, enum lcd_action_type action,
- void *data)
-{
- switch (action) {
- case LAT_BRIGHTNESS:
- set_brightness(ops, (int)data);
- break;
- case LAT_POWER:
- set_power(ops, (int)data);
- break;
- default:
- printk(KERN_INFO "LCD energy error: action=%d\n", action);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * @brief Get the array size of LCD
- *
- * @param ops LCD operations
- * @return Array size
- */
-size_t get_lcd_size_array(struct lcd_ops *ops)
-{
- struct lcd_priv_data *lcd = get_lcd_priv(ops);
-
- return lcd->tms_brt_cnt;
-}
-
-/**
- * @brief Get an array of times
- *
- * @param ops LCD operations
- * @param array_time[out] Array of times
- * @return Void
- */
-void get_lcd_array_time(struct lcd_ops *ops, u64 *array_time)
-{
- struct lcd_priv_data *lcd = get_lcd_priv(ops);
- int i;
-
- spin_lock(&lcd->lock_tms);
- for (i = 0; i < lcd->tms_brt_cnt; ++i)
- array_time[i] = tm_stat_running(&lcd->tms_brt[i]);
-
- if (lcd->power == PW_ON && lcd->brt_old != brt_no_init) {
- int old = lcd->brt_old;
- struct tm_stat *tm = &lcd->tms_brt[old];
-
- array_time[old] += get_ntime() - tm_stat_timestamp(tm);
- }
- spin_unlock(&lcd->lock_tms);
-}
-
-static int register_lcd(struct lcd_ops *ops)
-{
- int ret = 0;
-
- ops->priv = create_lcd_priv(ops, brt_cnt);
-
- /* TODO: create init_func() for 'struct rational' */
- ops->min_coef.num = 1;
- ops->min_coef.denom = 1;
- ops->max_coef.num = 1;
- ops->max_coef.denom = 1;
-
- ops->notifier = func_notifier_lcd;
-
- ret = register_lcd_debugfs(ops);
- if (ret)
- destroy_lcd_priv(ops->priv);
-
- return ret;
-}
-
-static void unregister_lcd(struct lcd_ops *ops)
-{
- unregister_lcd_debugfs(ops);
- destroy_lcd_priv(ops->priv);
-}
-
-
-
-
-/* ============================================================================
- * === LCD_INIT/LCD_EXIT ===
- * ============================================================================
- */
-typedef struct lcd_ops *(*get_ops_t)(void);
-
-DEFINITION_LCD_FUNC;
-
-get_ops_t lcd_ops[] = DEFINITION_LCD_ARRAY;
-enum { lcd_ops_cnt = sizeof(lcd_ops) / sizeof(get_ops_t) };
-
-enum ST_LCD_OPS {
- SLO_REGISTER = 1 << 0,
- SLO_SET = 1 << 1
-};
-
-static DEFINE_MUTEX(lcd_lock);
-static enum ST_LCD_OPS stat_lcd_ops[lcd_ops_cnt];
-
-static void do_lcd_exit(void)
-{
- int i;
- struct lcd_ops *ops;
-
- mutex_lock(&lcd_lock);
- for (i = 0; i < lcd_ops_cnt; ++i) {
- ops = lcd_ops[i]();
-
- if (stat_lcd_ops[i] & SLO_SET) {
- ops->unset(ops);
- stat_lcd_ops[i] &= ~SLO_SET;
- }
-
- if (stat_lcd_ops[i] & SLO_REGISTER) {
- unregister_lcd(ops);
- stat_lcd_ops[i] &= ~SLO_REGISTER;
- }
- }
- mutex_unlock(&lcd_lock);
-}
-
-/**
- * @brief LCD deinitialization
- *
- * @return Void
- */
-void lcd_exit(void)
-{
- do_lcd_exit();
-}
-
-static int do_lcd_init(void)
-{
- int i, ret, count = 0;
- struct lcd_ops *ops;
-
- mutex_lock(&lcd_lock);
- for (i = 0; i < lcd_ops_cnt; ++i) {
- ops = lcd_ops[i]();
- if (ops == NULL) {
- printk(KERN_INFO "error %s [ops == NULL]\n", __func__);
- continue;
- }
-
- if (0 == ops->check(ops)) {
- printk(KERN_INFO "error checking %s\n", ops->name);
- continue;
- }
-
- ret = register_lcd(ops);
- if (ret) {
- printk(KERN_INFO "error register_lcd %s\n", ops->name);
- continue;
- }
-
- stat_lcd_ops[i] |= SLO_REGISTER;
- ++count;
- }
- mutex_unlock(&lcd_lock);
-
- return count ? 0 : -EPERM;
-}
-
-/**
- * @brief LCD initialization
- *
- * @return Error code
- */
-int lcd_init(void)
-{
- int ret;
-
- ret = do_lcd_init();
- if (ret)
- printk(KERN_INFO "LCD is not supported\n");
-
- return ret;
-}
-
-
-
-/* ============================================================================
- * === LCD_SET_ENERGY/LCD_UNSET_ENERGY ===
- * ============================================================================
- */
-
-/**
- * @brief Start measuring the energy consumption of LСD
- *
- * @return Error code
- */
-int lcd_set_energy(void)
-{
- int i, ret, count = 0;
- struct lcd_ops *ops;
-
- mutex_lock(&lcd_lock);
- for (i = 0; i < lcd_ops_cnt; ++i) {
- ops = lcd_ops[i]();
- if (stat_lcd_ops[i] & SLO_REGISTER) {
- ret = ops->set(ops);
- if (ret) {
- printk(KERN_INFO "error %s set LCD energy",
- ops->name);
- continue;
- }
-
- set_brightness(ops, ops->get(ops, LPD_BRIGHTNESS));
- set_power(ops, ops->get(ops, LPD_POWER));
-
- stat_lcd_ops[i] |= SLO_SET;
- ++count;
- }
- }
- mutex_unlock(&lcd_lock);
-
- return count ? 0 : -EPERM;
-}
-
-/**
- * @brief Stop measuring the energy consumption of LСD
- *
- * @return Void
- */
-void lcd_unset_energy(void)
-{
- int i, ret;
- struct lcd_ops *ops;
-
- mutex_lock(&lcd_lock);
- for (i = 0; i < lcd_ops_cnt; ++i) {
- ops = lcd_ops[i]();
- if (stat_lcd_ops[i] & SLO_SET) {
- ret = ops->unset(ops);
- if (ret)
- printk(KERN_INFO "error %s unset LCD energy",
- ops->name);
-
- clean_brightness(ops);
- stat_lcd_ops[i] &= ~SLO_SET;
- }
- }
- mutex_unlock(&lcd_lock);
-}
+++ /dev/null
-#ifndef _LCD_BASE_H
-#define _LCD_BASE_H
-
-/**
- * @file energy/lcd/lcd_base.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- * Description of the interface for interacting with LСD
- */
-
-
-#include <linux/errno.h>
-#include <energy/rational_debugfs.h>
-
-
-/** Description of actions */
-enum lcd_action_type {
- LAT_BRIGHTNESS, /**< LCD brightness */
- LAT_POWER /**< LCD power */
-};
-
-
-/** Description of parameters */
-enum lcd_parameter_type {
- LPD_MIN_BRIGHTNESS, /**< minimum brightness value */
- LPD_MAX_BRIGHTNESS, /**< maximum brightness value */
- LPD_BRIGHTNESS, /**< current brightness value */
-
- LPD_POWER /**< current power value */
-};
-
-struct lcd_ops;
-
-/**
- * @brief LCD callback type
- *
- * @param ops LCD operations
- * @return Error code
- */
-typedef int (*call_lcd)(struct lcd_ops *ops);
-
-/**
- * @brief LCD notifier type
- *
- * @param ops LCD operations
- * @param action Event type
- * @param data Date
- * @return Error code
- */
-typedef int (*notifier_lcd)(struct lcd_ops *ops, enum lcd_action_type action,
- void *data);
-
-/**
- * @brief LCD parameter type
- *
- * @param ops LCD operations
- * @param type Requested parameter type
- * @return Requested parameter value
- *
- */
-typedef unsigned long (*get_parameter_lcd)(struct lcd_ops *ops,
- enum lcd_parameter_type type);
-
-
-/**
- * @struct lcd_ops
- * @breaf set of operations available for LСD
- */
-struct lcd_ops {
- char *name; /**< LCD driver name */
- notifier_lcd notifier; /**< Notifier */
- get_parameter_lcd get; /**< Method to obtain the parameters */
-
- call_lcd check; /**< LCD check on device */
- call_lcd set; /**< LCD initialization */
- call_lcd unset; /**< LCD deinitialization */
-
- /* for debugfs */
- struct dentry *dentry; /**< Dentry of debugfs for this LCD */
- struct rational min_coef; /**< Minimum coefficient */
- struct rational max_coef; /**< Maximum coefficient */
-
- void *priv; /**< Private data */
-};
-
-size_t get_lcd_size_array(struct lcd_ops *ops);
-void get_lcd_array_time(struct lcd_ops *ops, u64 *array_time);
-
-int read_val(const char *path);
-
-int lcd_set_energy(void);
-void lcd_unset_energy(void);
-
-int lcd_init(void);
-void lcd_exit(void);
-
-#endif /* _LCD_BASE_H */
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * energy/lcd/lcd_debugfs.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <energy/lcd/lcd_base.h>
-#include <energy/debugfs_energy.h>
-#include <energy/rational_debugfs.h>
-
-
-static int get_system(void *data, u64 *val)
-{
- struct lcd_ops *ops = (struct lcd_ops *)data;
- const size_t size = get_lcd_size_array(ops);
- const size_t size_1 = size - 1;
- u64 i_max, j_min, t, e = 0;
- u64 *array_time;
- int i, j;
-
- array_time = kmalloc(sizeof(*array_time) * size, GFP_KERNEL);
- if (array_time == NULL)
- return -ENOMEM;
-
- get_lcd_array_time(ops, array_time);
-
- for (i = 0; i < size; ++i) {
- t = array_time[i];
-
- /* e = (i * max + (k - i) * min) * t / k */
- j = size_1 - i;
- i_max = div_u64(i * ops->max_coef.num * t,
- ops->max_coef.denom);
- j_min = div_u64(j * ops->min_coef.num * t,
- ops->min_coef.denom);
- e += div_u64(i_max + j_min, size_1);
- }
-
- kfree(array_time);
-
- *val = e;
-
- return 0;
-}
-
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_get_system, get_system, NULL, "%llu\n");
-
-
-static struct dentry *lcd_dir;
-
-/**
- * @brief Register LCD in debugfs
- *
- * @param ops LCD operations
- * @return Error code
- */
-int register_lcd_debugfs(struct lcd_ops *ops)
-{
- int ret;
- struct dentry *dentry, *system;
-
- if (lcd_dir == NULL)
- return -EINVAL;
-
- dentry = debugfs_create_dir(ops->name, lcd_dir);
- if (dentry == NULL)
- return -ENOMEM;
-
- ret = create_rational_files(dentry, &ops->min_coef,
- "min_num", "min_denom");
- if (ret)
- goto fail;
-
- ret = create_rational_files(dentry, &ops->max_coef,
- "max_num", "max_denom");
- if (ret)
- goto fail;
-
- system = debugfs_create_file("system", 0600, dentry, (void *)ops,
- &fops_get_system);
- if (system == NULL)
- goto fail;
-
- ops->dentry = dentry;
-
- return 0;
-fail:
- debugfs_remove_recursive(dentry);
- return -ENOMEM;
-}
-
-/**
- * @brief Unregister LCD in debugfs
- *
- * @param ops LCD operations
- * @return Void
- */
-void unregister_lcd_debugfs(struct lcd_ops *ops)
-{
- debugfs_remove_recursive(ops->dentry);
-}
-
-/**
- * @brief Destroy debugfs for LCD
- *
- * @return Void
- */
-void exit_lcd_debugfs(void)
-{
- if (lcd_dir)
- debugfs_remove_recursive(lcd_dir);
-
- lcd_dir = NULL;
-}
-
-/**
- * @brief Create debugfs for LCD
- *
- * @param dentry Dentry
- * @return Error code
- */
-int init_lcd_debugfs(struct dentry *energy_dir)
-{
- lcd_dir = debugfs_create_dir("lcd", energy_dir);
- if (lcd_dir == NULL)
- return -ENOMEM;
-
- return 0;
-}
+++ /dev/null
-#ifndef _LCD_DEBUGFS_H
-#define _LCD_DEBUGFS_H
-
-/**
- * @file energy/lcd/lcd_debugfs.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- * Debugfs for LСD
- *
- */
-
-
-struct dentry;
-struct lcd_ops;
-
-int register_lcd_debugfs(struct lcd_ops *ops);
-void unregister_lcd_debugfs(struct lcd_ops *ops);
-
-int init_lcd_debugfs(struct dentry *energy_dir);
-void exit_lcd_debugfs(void);
-
-#endif /* _LCD_DEBUGFS_H */
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * energy/lcd/maru.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <kprobe/swap_kprobes.h>
-#include <linux/backlight.h>
-#include "lcd_base.h"
-
-
-
-static const char path_backlight[] =
- "/sys/class/backlight/emulator/brightness";
-static const char path_backlight_min[] =
- "/sys/class/backlight/emulator/min_brightness";
-static const char path_backlight_max[] =
- "/sys/class/backlight/emulator/max_brightness";
-static const char path_power[] =
- "/sys/class/lcd/emulator/lcd_power";
-
-static const char * const all_path[] = {
- path_backlight,
- path_backlight_min,
- path_backlight_max,
- path_power
-};
-
-enum {
- all_path_cnt = sizeof(all_path) / sizeof(char *)
-};
-
-
-static int maru_check(struct lcd_ops *ops)
-{
- int i;
-
- for (i = 0; i < all_path_cnt; ++i) {
- int ret = read_val(all_path[i]);
-
- if (IS_ERR_VALUE(ret))
- return 0;
- }
-
- return 1;
-}
-
-static unsigned long maru_get_parameter(struct lcd_ops *ops,
- enum lcd_parameter_type type)
-{
- switch (type) {
- case LPD_MIN_BRIGHTNESS:
- return read_val(path_backlight_min);
- case LPD_MAX_BRIGHTNESS:
- return read_val(path_backlight_max);
- case LPD_BRIGHTNESS:
- return read_val(path_backlight);
- case LPD_POWER:
- return read_val(path_power);
- default:
- return -EINVAL;
- }
-}
-
-
-
-
-
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-
-static struct kretprobe set_backlight_krp = {
- .kp.symbol_name = "marubl_send_intensity",
- .entry_handler = entry_handler_set_backlight,
- .handler = ret_handler_set_backlight,
- .data_size = sizeof(int)
-};
-
-
-
-
-
-static int maru_set(struct lcd_ops *ops)
-{
- return swap_register_kretprobe(&set_backlight_krp);
-}
-
-static int maru_unset(struct lcd_ops *ops)
-{
- swap_unregister_kretprobe(&set_backlight_krp);
- return 0;
-}
-
-static struct lcd_ops maru_ops = {
- .name = "maru",
- .check = maru_check,
- .set = maru_set,
- .unset = maru_unset,
- .get = maru_get_parameter
-};
-
-struct lcd_ops *LCD_MAKE_FNAME(maru)(void)
-{
- return &maru_ops;
-}
-
-
-
-
-
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int *brightness = (int *)ri->data;
- struct backlight_device *bd;
-
- bd = (struct backlight_device *)swap_get_karg(regs, 0);
- *brightness = bd->props.brightness;
-
- return 0;
-}
-
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int ret = regs_return_value(regs);
- int *brightness = (int *)ri->data;
-
- if (!ret && maru_ops.notifier)
- maru_ops.notifier(&maru_ops, LAT_BRIGHTNESS,
- (void *)*brightness);
-
- return 0;
-}
+++ /dev/null
-#include <kprobe/swap_kprobes.h>
-#include "lcd_base.h"
-
-
-static const char path_backlight[] =
- "/sys/class/backlight/s6e8aa0-bl/brightness";
-static const char path_backlight_min[] =
- "/sys/class/backlight/s6e8aa0-bl/min_brightness";
-static const char path_backlight_max[] =
- "/sys/class/backlight/s6e8aa0-bl/max_brightness";
-static const char path_power[] =
- "/sys/class/lcd/s6e8aa0/lcd_power";
-
-static const char * const all_path[] = {
- path_backlight,
- path_backlight_min,
- path_backlight_max,
- path_power
-};
-
-enum {
- all_path_cnt = sizeof(all_path) / sizeof(char *)
-};
-
-
-
-static int s6e8aa0_check(struct lcd_ops *ops)
-{
- int i;
-
- for (i = 0; i < all_path_cnt; ++i) {
- int ret = read_val(all_path[i]);
-
- if (IS_ERR_VALUE(ret))
- return 0;
- }
-
- return 1;
-}
-
-static unsigned long s6e8aa0_get_parameter(struct lcd_ops *ops,
- enum lcd_parameter_type type)
-{
- switch (type) {
- case LPD_MIN_BRIGHTNESS:
- return read_val(path_backlight_min);
- case LPD_MAX_BRIGHTNESS:
- return read_val(path_backlight_max);
- case LPD_BRIGHTNESS:
- return read_val(path_backlight);
- case LPD_POWER:
- return read_val(path_power);
- default:
- return -EINVAL;
- }
-}
-
-
-
-static int entry_handler_set_power(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-static int ret_handler_set_power(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-
-static struct kretprobe set_power_krp = {
- .kp.symbol_name = "s6e8aa0_set_power",
- .entry_handler = entry_handler_set_power,
- .handler = ret_handler_set_power,
- .data_size = sizeof(int)
-};
-
-
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-
-static struct kretprobe set_backlight_krp = {
- .kp.symbol_name = "s6e8aa0_gamma_ctrl",
- .entry_handler = entry_handler_set_backlight,
- .handler = ret_handler_set_backlight,
- .data_size = sizeof(int)
-};
-
-int s6e8aa0_set(struct lcd_ops *ops)
-{
- int ret;
-
- ret = swap_register_kretprobe(&set_power_krp);
- if (ret)
- return ret;
-
- ret = swap_register_kretprobe(&set_backlight_krp);
- if (ret)
- swap_unregister_kretprobe(&set_power_krp);
-
- return ret;
-}
-
-int s6e8aa0_unset(struct lcd_ops *ops)
-{
- swap_unregister_kretprobe(&set_backlight_krp);
- swap_unregister_kretprobe(&set_power_krp);
-
- return 0;
-}
-
-static struct lcd_ops s6e8aa0_ops = {
- .name = "s6e8aa0",
- .check = s6e8aa0_check,
- .set = s6e8aa0_set,
- .unset = s6e8aa0_unset,
- .get = s6e8aa0_get_parameter
-};
-
-struct lcd_ops *LCD_MAKE_FNAME(s6e8aa0)(void)
-{
- return &s6e8aa0_ops;
-}
-
-
-
-
-
-/* ============================================================================
- * === POWER ===
- * ============================================================================
- */
-static int entry_handler_set_power(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int *power = (int *)ri->data;
-
- *power = (int)swap_get_karg(regs, 1);
-
- return 0;
-}
-
-static int ret_handler_set_power(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int ret = regs_return_value(regs);
- int *power = (int *)ri->data;
-
- if (!ret && s6e8aa0_ops.notifier)
- s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_POWER, (void *)*power);
-
- return 0;
-}
-
-
-
-
-
-/* ============================================================================
- * === BACKLIGHT ===
- * ============================================================================
- */
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int *brightness = (int *)ri->data;
- *brightness = (int)swap_get_karg(regs, 1);
-
- return 0;
-}
-
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int ret = regs_return_value(regs);
- int *brightness = (int *)ri->data;
-
- if (!ret && s6e8aa0_ops.notifier)
- s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_BRIGHTNESS,
- (void *)*brightness);
-
- return 0;
-}
+++ /dev/null
-#include <kprobe/swap_kprobes.h>
-#include <linux/backlight.h>
-#include "lcd_base.h"
-
-
-static const char path_backlight[] =
- "/sys/class/backlight/s6e8aa0-bl/brightness";
-static const char path_backlight_max[] =
- "/sys/class/backlight/s6e8aa0-bl/max_brightness";
-static const char path_power[] =
- "/sys/class/lcd/s6e8aa0/lcd_power";
-
-static const char * const all_path[] = {
- path_backlight,
- path_backlight_max,
- path_power
-};
-
-enum {
- all_path_cnt = sizeof(all_path) / sizeof(char *)
-};
-
-
-
-static int s6e8aa0_check(struct lcd_ops *ops)
-{
- int i;
-
- for (i = 0; i < all_path_cnt; ++i) {
- int ret = read_val(all_path[i]);
-
- if (IS_ERR_VALUE(ret))
- return 0;
- }
-
- return 1;
-}
-
-static unsigned long s6e8aa0_get_parameter(struct lcd_ops *ops,
- enum lcd_parameter_type type)
-{
- switch (type) {
- case LPD_MIN_BRIGHTNESS:
- return 0;
- case LPD_MAX_BRIGHTNESS:
- return read_val(path_backlight_max);
- case LPD_BRIGHTNESS:
- return read_val(path_backlight);
- case LPD_POWER:
- return read_val(path_power);
- }
-
- return -EINVAL;
-}
-
-
-
-static int entry_handler_set_power(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-static int ret_handler_set_power(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-
-static struct kretprobe set_power_krp = {
- .kp.symbol_name = "s6e8aa0_set_power",
- .entry_handler = entry_handler_set_power,
- .handler = ret_handler_set_power,
- .data_size = sizeof(int)
-};
-
-
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-
-static struct kretprobe set_backlight_krp = {
- .kp.symbol_name = "s6e8aa0_update_status",
- .entry_handler = entry_handler_set_backlight,
- .handler = ret_handler_set_backlight,
- .data_size = sizeof(int)
-};
-
-int s6e8aa0_set(struct lcd_ops *ops)
-{
- int ret;
-
- ret = swap_register_kretprobe(&set_power_krp);
- if (ret)
- return ret;
-
- ret = swap_register_kretprobe(&set_backlight_krp);
- if (ret)
- swap_unregister_kretprobe(&set_power_krp);
-
- return ret;
-}
-
-int s6e8aa0_unset(struct lcd_ops *ops)
-{
- swap_unregister_kretprobe(&set_backlight_krp);
- swap_unregister_kretprobe(&set_power_krp);
-
- return 0;
-}
-
-static struct lcd_ops s6e8aa0_ops = {
- .name = "s6e8aa0_panel",
- .check = s6e8aa0_check,
- .set = s6e8aa0_set,
- .unset = s6e8aa0_unset,
- .get = s6e8aa0_get_parameter
-};
-
-struct lcd_ops *LCD_MAKE_FNAME(s6e8aa0_panel)(void)
-{
- return &s6e8aa0_ops;
-}
-
-
-
-
-
-/* ============================================================================
- * === POWER ===
- * ============================================================================
- */
-static int entry_handler_set_power(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int *power = (int *)ri->data;
-
- *power = (int)swap_get_karg(regs, 1);
-
- return 0;
-}
-
-static int ret_handler_set_power(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int ret = regs_return_value(regs);
- int *power = (int *)ri->data;
-
- if (!ret && s6e8aa0_ops.notifier)
- s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_POWER,
- (void *)*power);
-
- return 0;
-}
-
-
-
-
-
-/* ============================================================================
- * === BACKLIGHT ===
- * ============================================================================
- */
-static int entry_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int *brightness = (int *)ri->data;
- struct backlight_device *bd;
-
- bd = (struct backlight_device *)swap_get_karg(regs, 0);
- *brightness = bd->props.brightness;
-
- return 0;
-}
-
-static int ret_handler_set_backlight(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- int ret = regs_return_value(regs);
- int *brightness = (int *)ri->data;
-
- if (!ret && s6e8aa0_ops.notifier)
- s6e8aa0_ops.notifier(&s6e8aa0_ops, LAT_BRIGHTNESS,
- (void *)*brightness);
-
- return 0;
-}
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * energy/rational_debugfs.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/dcache.h>
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include "debugfs_energy.h"
-#include "rational_debugfs.h"
-
-
-static int denom_set(void *data, u64 val)
-{
- if (val == 0)
- return -EINVAL;
-
- *(u64 *)data = val;
- return 0;
-}
-
-static int denom_get(void *data, u64 *val)
-{
- *val = *(u64 *)data;
- return 0;
-}
-
-SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_denom, denom_get, denom_set, "%llu\n");
-
-/**
- * @brief Create file in debugfs for rational struct
- *
- * @param parent Dentry parent
- * @param r Pointer to the rational struct
- * @param num_name File name of numerator
- * @param denom_name File name of denominator
- * @return Error code
- */
-int create_rational_files(struct dentry *parent, struct rational *r,
- const char *num_name, const char *denom_name)
-{
- struct dentry *d_num, *d_denom;
-
- d_num = debugfs_create_u64(num_name, 0600, parent, &r->num);
- if (d_num == NULL)
- return -ENOMEM;
-
- d_denom = debugfs_create_file(denom_name, 0600, parent, &r->denom,
- &fops_denom);
- if (d_denom == NULL) {
- debugfs_remove(d_num);
- return -ENOMEM;
- }
-
- return 0;
-}
+++ /dev/null
-#ifndef _RATIONAL_DEBUGFS_H
-#define _RATIONAL_DEBUGFS_H
-
-/**
- * @file energy/rational_debugfs.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-
-#include <linux/types.h>
-
-
-/**
- * @struct rational
- * @brief Description of rational number
- */
-struct rational {
- u64 num; /**< Numerator */
- u64 denom; /**< Denominator */
-};
-
-
-/**
- * @def DEFINE_RATIONAL
- * Initialize of rational struct @hideinitializer
- */
-#define DEFINE_RATIONAL(rational_name) \
- struct rational rational_name = { \
- .num = 1, \
- .denom = 1 \
- }
-
-
-struct dentry;
-
-int create_rational_files(struct dentry *parent, struct rational *r,
- const char *num_name, const char *denom_name);
-
-
-#endif /* _RATIONAL_DEBUGFS_H */
+++ /dev/null
-#ifndef _TM_STAT_H
-#define _TM_STAT_H
-
-/**
- * @file energy/tm_stat.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYFIGHT
- * Copyright (C) Samsung Electronics, 2013
- *
- */
-
-
-#include <linux/types.h>
-#include <linux/time.h>
-
-
-/**
- * @struct tm_stat
- * @brief Description of statistic time
- */
-struct tm_stat {
- u64 timestamp; /**< Time stamp */
- u64 running; /**< Running time */
-};
-
-/**
- * @def DEFINE_TM_STAT
- * Initialize of tm_stat struct @hideinitializer
- */
-#define DEFINE_TM_STAT(tm_name) \
- struct tm_stat tm_name = { \
- .timestamp = 0, \
- .running = 0 \
- }
-
-
-static inline u64 get_ntime(void)
-{
- struct timespec ts;
- getnstimeofday(&ts);
- return timespec_to_ns(&ts);
-}
-
-static inline void tm_stat_init(struct tm_stat *tm)
-{
- tm->timestamp = 0;
- tm->running = 0;
-}
-
-static inline void tm_stat_set_timestamp(struct tm_stat *tm, u64 time)
-{
- tm->timestamp = time;
-}
-
-static inline u64 tm_stat_timestamp(struct tm_stat *tm)
-{
- return tm->timestamp;
-}
-
-static inline void tm_stat_update(struct tm_stat *tm, u64 time)
-{
- tm->running += time - tm->timestamp;
-}
-
-static inline u64 tm_stat_running(struct tm_stat *tm)
-{
- return tm->running;
-}
-
-static inline u64 tm_stat_current_running(struct tm_stat *tm, u64 now)
-{
- if (unlikely(now < tm->timestamp))
- printk(KERN_INFO "XXX %p WARNING now(%llu) < tmstmp(%llu)\n",
- tm, now, tm->timestamp);
- return tm->timestamp ? tm->running + now - tm->timestamp : tm->running;
-}
-
-#endif /* _TM_STAT_H */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_fbiprobe.o
-swap_fbiprobe-y := fbiprobe.o \
- fbi_msg.o
+++ /dev/null
-/**
- * fbiprobe/fbi_msg.c
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Packing and writing data.
- */
-
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <writer/swap_msg.h>
-
-struct msg_fbi {
- u32 var_id;
- u32 size;
- char var_data[0];
-} __packed;
-
-
-static char *pack_fbi_info(char *payload, unsigned long var_id, size_t size,
- char *msg_buf)
-{
- struct msg_fbi *fbi_m = (struct msg_fbi *)payload;
-
- fbi_m->var_id = var_id;
- fbi_m->size = size;
- if (size != 0) {
- /* FIXME Possible out of buffer! */
- memcpy(&fbi_m->var_data, msg_buf, size);
- }
-
- /*
- * If size is 0 that mean we cannot get data for this probe.
- * But we pack it like error code
- */
-
- return payload + sizeof(struct msg_fbi) + size;
-}
-
-void fbi_msg(unsigned long var_id, size_t size, char *msg_buf)
-{
- struct swap_msg *m;
- void *p;
- void *buf_end;
-
- m = swap_msg_get(MSG_FBI);
- p = swap_msg_payload(m);
-
- buf_end = pack_fbi_info(p, var_id, size, msg_buf);
-
- swap_msg_flush(m, buf_end - p);
-
- swap_msg_put(m);
-}
+++ /dev/null
-/*
- * @file fbiprobe/fbi_msg.h
- *
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * Function body instrumetation
- *
- */
-
-#ifndef __FBI_MSG_H__
-#define __FBI_MSG_H__
-
-#include <linux/types.h>
-
-void fbi_msg(unsigned long var_id, size_t size, char *msg_buf);
-
-#endif /* __FBI_MSG_H__ */
+++ /dev/null
-/*
- * @file fbiprobe/fbi_probe.h
- *
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Alexander Aksenov : FBI implement
- * 2014 Vitaliy Cherepanov: FBI implement, portage
- *
- * @section DESCRIPTION
- *
- * Function body instrumentation.
- *
- */
-
-#ifndef __FBI_PROBE_MODULE_H__
-#define __FBI_PROBE_MODULE_H__
-
-#include <linux/kernel.h>
-
-/* MESSAGES */
-
-#define MODULE_NAME "SWAP_FBI_PROBE"
-
-/* FBI_DEBUG_ON:
- * val | DEBUG | MSG | WARN | ERR | CRITICAL|
- * ----+-------+-----+------+-----+---------|
- * 0 | OFF | OFF | OFF | OFF | OFF |
- * 1 | OFF | OFF | OFF | OFF | ON |
- * 2 | OFF | OFF | OFF | ON | ON |
- * 3 | OFF | OFF | ON | ON | ON |
- * 4 | OFF | ON | ON | ON | ON |
- * 5 | ON | ON | ON | ON | ON |
- */
-
-#define FBI_DEBUG_LEVEL 3
-
-/** Prints debug message.*/
-#if (FBI_DEBUG_LEVEL >= 5)
-#define print_debug(msg, args...) \
- printk(KERN_DEBUG MODULE_NAME " DEBUG : " msg, ##args)
-#else
-#define print_debug(msg, args...)
-#endif
-
-/** Prints info message.*/
-#if (FBI_DEBUG_LEVEL >= 4)
-#define print_msg(msg, args...) \
- printk(KERN_INFO MODULE_NAME " : " msg, ##args)
-#else
-#define print_msg(msg, args...)
-#endif
-
-/** Prints warning message.*/
-#if (FBI_DEBUG_LEVEL >= 3)
-#define print_warn(msg, args...) \
- printk(KERN_WARNING MODULE_NAME " WARNING : " msg, ##args)
-#else
-#define print_warn(msg, args...)
-#endif
-
-/** Prints error message.*/
-#if (FBI_DEBUG_LEVEL >= 2)
-#define print_err(msg, args...) \
- printk(KERN_ERR MODULE_NAME " ERROR : " msg, ##args)
-#else
-#define print_err(msg, args...)
-#endif
-
-/** Prints critical error message.*/
-#if (FBI_DEBUG_LEVEL >= 1)
-#define print_crit(msg, args...) \
- printk(KERN_CRIT MODULE_NAME " CRITICAL : " msg, ##args)
-#else
-#define print_crit(msg, args...)
-#endif
-
-#endif /* __FBI_PROBE_MODULE_H__ */
+++ /dev/null
-/*
- * @file fbiprobe/fbi_probe.c
- *
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Alexander Aksenov : FBI implement
- * 2014 Vitaliy Cherepanov: FBI implement, portage
- *
- * @section DESCRIPTION
- *
- * Function body instrumetation
- *
- */
-
-#include "fbiprobe.h"
-#include "fbi_probe_module.h"
-#include "fbi_msg.h"
-#include "regs.h"
-
-#include <us_manager/us_manager.h>
-#include <us_manager/probes/probes.h>
-#include <us_manager/probes/register_probes.h>
-
-#include <uprobe/swap_uprobes.h>
-#include <us_manager/sspt/ip.h>
-
-#include <kprobe/swap_kprobes_deps.h>
-#include <linux/module.h>
-
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/dcache.h>
-#include <linux/mm_types.h>
-
-#include <us_manager/sspt/sspt_page.h>
-#include <us_manager/sspt/sspt_file.h>
-
-#define DIRECT_ADDR (0xFF)
-#define MAX_STRING_LEN (512)
-
-/* on fails. return NULL, set size to 0 */
-/* you shoud free allocated data buffer */
-static char *fbi_probe_alloc_and_read_from_addr(const struct fbi_var_data *fbid,
- unsigned long addr,
- uint32_t *size)
-{
- uint8_t i, j;
- char *buf = NULL;
- struct fbi_step *step;
-
- *size = 0;
-
- /* get final variable address */
- step = fbid->steps;
- for (i = 0; i != fbid->steps_count; i++) {
- /* dereference */
- for (j = 0; j != step->ptr_order; j++) {
- unsigned long new_addr;
- /* equel to: addr = *addr */
- if (!read_proc_vm_atomic(current, addr, &new_addr,
- sizeof(new_addr))) {
- print_warn("p = 0x%lx step #%d ptr_order #%d\n",
- addr, i + 1, j + 1);
- goto exit_fail;
- }
- addr = new_addr;
- print_debug("dereference addr = 0x%lx;\n", addr);
- }
-
- /* offset */
- addr += step->data_offset;
- print_debug("addr + offset = 0x%lx;\n", addr);
- step++;
- }
-
- /* calculate data size */
- if (fbid->data_size == 0) {
- /*
- * that mean variable is string and
- * we need to calculate string length
- */
-
- *size = strnlen_user((const char __user *)addr, MAX_STRING_LEN);
- if (*size == 0) {
- print_warn("Cannot get string from 0x%lx\n", addr);
- goto exit_fail;
- }
- } else {
- /* else use size from fbi struct */
- *size = fbid->data_size;
- }
-
- buf = kmalloc(*size, GFP_KERNEL);
- if (buf == NULL) {
- print_warn("Not enough memory\n");
- goto exit_fail_size_0;
- }
-
- if (!read_proc_vm_atomic(current, addr, buf, *size)) {
- print_warn("Error reading data at 0x%lx, task %d\n",
- addr, current->pid);
- goto exit_fail_free_buf;
- }
-
- if (fbid->data_size == 0) {
- /*
- * that mean variable is string and
- * we need to add terminate '\0'
- */
- buf[*size - 1] = '\0';
- }
-
- return buf;
-
-exit_fail_free_buf:
- kfree(buf);
- buf = NULL;
-exit_fail_size_0:
- *size = 0;
-exit_fail:
- return NULL;
-
-}
-
-static int fbi_probe_get_data_from_reg(const struct fbi_var_data *fbi_i,
- struct pt_regs *regs)
-{
- unsigned long *reg_ptr;
-
- reg_ptr = get_ptr_by_num(regs, fbi_i->reg_n);
- if (reg_ptr == NULL) {
- print_err("fbi_probe_get_data_from_reg: Wrong register number!\n");
- return 0;
- }
-
- fbi_msg(fbi_i->var_id, fbi_i->data_size, (char *)reg_ptr);
-
- return 0;
-}
-
-static int fbi_probe_get_data_from_ptrs(const struct fbi_var_data *fbi_i,
- struct pt_regs *regs)
-{
- unsigned long *reg_ptr;
- unsigned long addr;
- uint32_t size = 0;
- void *buf = NULL;
-
- reg_ptr = get_ptr_by_num(regs, fbi_i->reg_n);
- if (reg_ptr == NULL) {
- print_err("fbi_probe_get_data_from_ptrs: Wrong register number!\n");
- goto send_msg;
- }
-
- addr = *reg_ptr + fbi_i->reg_offset;
- print_warn("reg = %p; off = 0x%llx; addr = 0x%lx!\n", reg_ptr,
- fbi_i->reg_offset, addr);
-
- buf = fbi_probe_alloc_and_read_from_addr(fbi_i, addr, &size);
-
-send_msg:
- /* If buf is NULL size will be 0.
- * That mean we cannot get data for this probe.
- * But we should send probe message with packed data size 0
- * as error message.
- */
- fbi_msg(fbi_i->var_id, size, buf);
-
- if (buf != NULL)
- kfree(buf);
- else
- print_err("cannot get data from ptrs\n");
-
- return 0;
-}
-
-static struct vm_area_struct *find_vma_exe_by_dentry(struct mm_struct *mm,
- struct dentry *dentry)
-{
- struct vm_area_struct *vma;
-
- /* FIXME: down_write(&mm->mmap_sem); up_write(&mm->mmap_sem); */
- /* TODO FILTER vma */
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- if (vma->vm_file &&
- (vma->vm_file->f_dentry == dentry))
- /* found */
- goto exit;
- }
-
- /* not found */
- vma = NULL;
-exit:
- return vma;
-}
-
-static int fbi_probe_get_data_from_direct_addr(const struct fbi_var_data *fbi_i,
- struct us_ip *ip,
- struct pt_regs *regs)
-{
- struct vm_area_struct *vma;
- unsigned long addr;
- uint32_t size = 0;
- char *buf;
-
- /* register offset is global address */
- vma = find_vma_exe_by_dentry(current->mm, ip->page->file->dentry);
- if (vma == NULL) {
- print_warn("cannot locate dentry\n");
- goto exit;
- }
-
- addr = vma->vm_start + fbi_i->reg_offset;
-
- print_debug("DIRECT_ADDR reg_offset = %llx\n", fbi_i->reg_offset);
- print_debug("DIRECT_ADDR vm_start = %lx\n", vma->vm_start);
- print_debug("DIRECT_ADDR res_addr = %lx\n", addr);
-
- buf = fbi_probe_alloc_and_read_from_addr(fbi_i, addr, &size);
- /* If buf is NULL size will be 0.
- * That mean we cannot get data for this probe.
- * But we should send probe message with packed data size 0
- * as error message.
- */
- fbi_msg(fbi_i->var_id, size, buf);
-
- if (buf != NULL) {
- kfree(buf);
- } else {
- print_warn("get data by direct addr failed (0x%lx :0x%llx)\n",
- addr, fbi_i->reg_offset);
- }
-exit:
- return 0;
-}
-
-static int fbi_probe_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct uprobe *up = container_of(p, struct uprobe, kp);
- struct us_ip *ip = container_of(up, struct us_ip, uprobe);
- struct fbi_info *fbi_i = &ip->info->fbi_i;
- struct fbi_var_data *fbi_d = NULL;
- uint8_t i;
-
- if (ip->info->probe_type != SWAP_FBIPROBE) {
- /* How this can occure? Doesn't matter, just print and go */
- print_err("Not FBI probe in FBI handler!\n");
- return 0;
- }
-
- for (i = 0; i != fbi_i->var_count; i++) {
- fbi_d = &fbi_i->vars[i];
- if (fbi_d->reg_n == DIRECT_ADDR) {
- if (0 != fbi_probe_get_data_from_direct_addr(fbi_d, ip,
- regs))
- print_err("fbi_probe_get_data_from_direct_addr error\n");
- } else if (fbi_d->steps_count == 0) {
- if (0 != fbi_probe_get_data_from_reg(fbi_d, regs))
- print_err("fbi_probe_get_data_from_reg error\n");
- } else {
- if (0 != fbi_probe_get_data_from_ptrs(fbi_d, regs))
- print_err("fbi_probe_get_data_from_ptrs error\n");
- }
- }
-
- return 0;
-}
-
-/* FBI probe interfaces */
-void fbi_probe_cleanup(struct probe_info *probe_i)
-{
- uint8_t i;
- struct fbi_info *fbi_i = &(probe_i->fbi_i);
-
- for (i = 0; i != fbi_i->var_count; i++) {
- if (fbi_i->vars[i].steps != NULL) {
- if (fbi_i->vars[i].steps != NULL)
- kfree(fbi_i->vars[i].steps);
- fbi_i->vars[i].steps = NULL;
- fbi_i->vars[i].steps_count = 0;
- }
- }
-
- kfree(fbi_i->vars);
- fbi_i->vars = NULL;
-}
-
-void fbi_probe_init(struct us_ip *ip)
-{
- ip->uprobe.kp.pre_handler = (kprobe_pre_handler_t)fbi_probe_handler;
-}
-
-void fbi_probe_uninit(struct us_ip *ip)
-{
- if (ip != NULL)
- fbi_probe_cleanup(ip->info);
-}
-
-static int fbi_probe_register_probe(struct us_ip *ip)
-{
- return swap_register_uprobe(&ip->uprobe);
-}
-
-static void fbi_probe_unregister_probe(struct us_ip *ip, int disarm)
-{
- __swap_unregister_uprobe(&ip->uprobe, disarm);
-}
-
-static struct uprobe *fbi_probe_get_uprobe(struct us_ip *ip)
-{
- return &ip->uprobe;
-}
-
-int fbi_probe_copy(struct probe_info *dest, const struct probe_info *source)
-{
- uint8_t steps_count;
- size_t steps_size;
- size_t vars_size;
- struct fbi_var_data *vars;
- struct fbi_step *steps_source;
- struct fbi_step *steps_dest = NULL;
- uint8_t i, n;
- int ret = 0;
-
- memcpy(dest, source, sizeof(*source));
-
- vars_size = source->fbi_i.var_count * sizeof(*source->fbi_i.vars);
- vars = kmalloc(vars_size, GFP_KERNEL);
- if (vars == NULL)
- return -ENOMEM;
-
- memcpy(vars, source->fbi_i.vars, vars_size);
-
- for (i = 0; i != source->fbi_i.var_count; i++) {
- steps_dest = NULL;
- steps_count = vars[i].steps_count;
- steps_size = sizeof(*steps_source) * steps_count;
- steps_source = vars[i].steps;
-
- if (steps_size != 0 && steps_source != NULL) {
- steps_dest = kmalloc(steps_size, GFP_KERNEL);
- if (steps_dest == NULL) {
- print_err("can not alloc data\n");
- n = i;
- ret = -ENOMEM;
- goto err;
- }
-
- memcpy(steps_dest, steps_source, steps_size);
- }
- vars[i].steps = steps_dest;
- }
-
- dest->fbi_i.vars = vars;
-
- return ret;
-err:
- for (i = 0; i < n; i++)
- kfree(vars[i].steps);
- kfree(vars);
- return ret;
-}
-
-/* Register */
-static struct probe_iface fbi_probe_iface = {
- .init = fbi_probe_init,
- .uninit = fbi_probe_uninit,
- .reg = fbi_probe_register_probe,
- .unreg = fbi_probe_unregister_probe,
- .get_uprobe = fbi_probe_get_uprobe,
- .copy = fbi_probe_copy,
- .cleanup = fbi_probe_cleanup
-};
-
-static int __init fbiprobe_module_init(void)
-{
- int ret = 0;
- ret = swap_register_probe_type(SWAP_FBIPROBE, &fbi_probe_iface);
- print_debug("Init done. Result=%d\n", ret);
- return ret;
-}
-
-static void __exit fbiprobe_module_exit(void)
-{
- swap_unregister_probe_type(SWAP_FBIPROBE);
-}
-
-module_init(fbiprobe_module_init);
-module_exit(fbiprobe_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP fbiprobe");
-MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>; Vitaliy Cherepanov <v.cherepanov@samsung.com>");
-
+++ /dev/null
-/*
- * @file fbi_probe/fbi_probe.h
- *
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Alexander Aksenov : FBI implement
- * 2014 Vitaliy Cherepanov: FBI implement, portage
- *
- * @section DESCRIPTION
- *
- * Function body instrumentation.
- *
- */
-
-#ifndef __FBI_PROBE_H__
-#define __FBI_PROBE_H__
-
-#include <linux/types.h>
-
-/* FBI step */
-struct fbi_step {
- uint8_t ptr_order; /* Specifies what is located on the address:
- * ptr_order = 0 - variable
- * ptr_order = 1 - pointer to variable
- * ptr_order = 2 - pointer to pointer
- * etc. */
-
- uint64_t data_offset;
-} __packed;
-
-/* FBI var data */
-struct fbi_var_data {
- /* Variable position is evaluated by the following rule:
- * var_position = *(pointer_to_register) - reg_offset
- * It is expected that the offset is not null only when we're taking
- * var value from stack.
- */
- uint64_t var_id; /* Variable identifier
- * Used to specify var */
- uint64_t reg_offset; /* Offset relative to the registers value
- * address, specified with reg_n */
- uint8_t reg_n; /* Register number. Hope times of cpu
- * with more than 2 million ones are very
- * far from us */
- uint32_t data_size; /* Data size to be read */
-
- uint8_t steps_count; /* Count of steps to extract variable
- * value */
- struct fbi_step *steps; /* extract steps */
-};
-
-/* FBI info */
-struct fbi_info {
- uint8_t var_count;
- struct fbi_var_data *vars;
-};
-
-#endif /* __FBI_PROBE_H__ */
+++ /dev/null
-/*
- * @file fbiprobe/fbi_probe.h
- *
- * @author Aleksandr Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Alexander Aksenov : FBI implement
- * 2014 Vitaliy Cherepanov: FBI portage
- *
- * @section DESCRIPTION
- *
- * Function body instrumetation
- *
- */
-
-#ifndef __REGS_H__
-#define __REGS_H__
-
-#include <linux/ptrace.h>
-
-#include "fbi_probe_module.h"
-/* This function is used to compare register number and its name on x86 arch.
- * For ARM it is dumb.
- * List of registers and their nums on x86:
- * ax 0
- * bx 1
- * cx 2
- * dx 3
- * si 4
- * di 5
- * bp 6
- * sp 7
- */
-
-static inline unsigned long *get_ptr_by_num(struct pt_regs *regs,
- unsigned char reg_num)
-{
- unsigned long *reg = NULL;
- /* FIXME: bad way to use "sizeof(long) " */
- if (reg_num < sizeof(struct pt_regs) / sizeof(long)) {
- reg = (unsigned long *)regs;
- reg = ®[reg_num];
- }
-
- return reg;
-}
-
-#endif /* __REGS_H__ */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_kprobe.o
-swap_kprobe-y := swap_kprobes.o \
- swap_kprobes_deps.o \
- swap_slots.o
-
-### ARM
-swap_kprobe-$(CONFIG_ARM) += arch/arm/swap-asm/swap_kprobes.o \
- arch/arm/swap-asm/trampoline_arm.o
-ifeq ($(CONFIG_STRICT_MEMORY_RWX), y)
-swap_kprobe-$(CONFIG_ARM) += arch/arm/swap-asm/memory_rwx.o
-endif #ifeq ($(CONFIG_STRICT_MEMORY_RWX), y)
-
-
-### X86
-swap_kprobe-$(CONFIG_X86) += arch/x86/swap-asm/swap_kprobes.o
+++ /dev/null
-/*
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- */
-
-
-#include <asm/page.h>
-#include <asm/cacheflush.h>
-#include <asm/mmu_writeable.h>
-
-
-#include <ksyms/ksyms.h>
-
-
-static struct mm_struct *swap_init_mm;
-static int (*swap_set_memory_ro)(unsigned long addr, int numpages);
-static int (*swap_set_memory_rw)(unsigned long addr, int numpages);
-
-
-static int get_pte_cb(pte_t *ptep, pgtable_t token,
- unsigned long addr, void *data)
-{
- *(pte_t *)data = *ptep;
-
- return 1;
-}
-
-static pte_t get_pte(unsigned long page_addr)
-{
- pte_t pte = 0;
-
- apply_to_page_range(swap_init_mm, page_addr,
- PAGE_SIZE, get_pte_cb, &pte);
-
- return pte;
-}
-
-static void write_to_module(unsigned long addr, unsigned long val)
-{
- unsigned long *maddr = (unsigned long *)addr;
- unsigned long page_addr = addr & PAGE_MASK;
- pte_t pte;
-
- pte = get_pte(page_addr);
- if (pte_write(pte) == 0) {
- unsigned long flags;
- DEFINE_SPINLOCK(mem_lock);
-
- spin_lock_irqsave(&mem_lock, flags);
- if (swap_set_memory_rw(page_addr, 1) == 0) {
- *maddr = val;
- swap_set_memory_ro(page_addr, 1);
- } else {
- printk(KERN_INFO "RWX: failed to write memory %08lx (%08lx)\n",
- addr, val);
- }
- spin_unlock_irqrestore(&mem_lock, flags);
- } else {
- *maddr = val;
- }
-
- flush_icache_range(addr, addr + sizeof(long));
-}
-
-void mem_rwx_write_u32(unsigned long addr, unsigned long val)
-{
- if (addr < MODULES_VADDR || addr >= MODULES_END) {
- /*
- * if addr doesn't belongs kernel space,
- * segmentation fault will occur
- */
- mem_text_write_kernel_word((long *)addr, val);
- } else {
- write_to_module(addr, val);
- }
-}
-
-int mem_rwx_once(void)
-{
- const char *sym;
-
- sym = "set_memory_ro";
- swap_set_memory_ro = (void *)swap_ksyms(sym);
- if (swap_set_memory_ro == NULL)
- goto not_found;
-
- sym = "set_memory_rw";
- swap_set_memory_rw = (void *)swap_ksyms(sym);
- if (swap_set_memory_rw == NULL)
- goto not_found;
-
- sym = "init_mm";
- swap_init_mm = (void *)swap_ksyms(sym);
- if (swap_init_mm == NULL)
- goto not_found;
-
- return 0;
-
-not_found:
- printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
- return -ESRCH;
-}
+++ /dev/null
-/**
- * @file kprobe/arch/asm-arm/memory_rwx.h
- *
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- */
-
-
-#ifndef _MEMORY_RWX_H
-#define _MEMORY_RWX_H
-
-
-int mem_rwx_once(void);
-void mem_rwx_write_u32(unsigned long addr, unsigned long val);
-
-
-#endif /* _MEMORY_RWX_H */
+++ /dev/null
-/**
- * kprobe/arch/asm-arm/swap_kprobes.c
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM/MIPS
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation; Support x86.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- * @author Alexander Shirshikov <a.shirshikov@samsung.com>: initial implementation for Thumb
- * @author Stanislav Andreev <s.andreev@samsung.com>: added time debug profiling support; BUG() message fix
- * @author Stanislav Andreev <s.andreev@samsung.com>: redesign of kprobe functionality -
- * kprobe_handler() now called via undefined instruction hooks
- * @author Stanislav Andreev <s.andreev@samsung.com>: hash tables search implemented for uprobes
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2014
- *
- * @section DESCRIPTION
- *
- * SWAP kprobe implementation for ARM architecture.
- */
-
-#include <linux/module.h>
-#include <linux/mm.h>
-
-#include "swap_kprobes.h"
-#include "trampoline_arm.h"
-#include <kprobe/swap_kprobes.h>
-
-#include <kprobe/swap_kdebug.h>
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <ksyms/ksyms.h>
-
-#include <asm/cacheflush.h>
-#include <asm/traps.h>
-#include <linux/ptrace.h>
-#include <linux/list.h>
-#include <linux/hash.h>
-
-
-#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
-#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
-
-
-static void (*__swap_register_undef_hook)(struct undef_hook *hook);
-static void (*__swap_unregister_undef_hook)(struct undef_hook *hook);
-
-static unsigned long get_addr_b(unsigned long insn, unsigned long addr)
-{
- /* real position less then PC by 8 */
- return (kprobe_opcode_t)((long)addr + 8 + branch_displacement(insn));
-}
-
-static int prep_pc_dep_insn_execbuf(kprobe_opcode_t *insns,
- kprobe_opcode_t insn, int uregs)
-{
- int i;
-
- if (uregs & 0x10) {
- int reg_mask = 0x1;
- /* search in reg list */
- for (i = 0; i < 13; i++, reg_mask <<= 1) {
- if (!(insn & reg_mask))
- break;
- }
- } else {
- for (i = 0; i < 13; i++) {
- if ((uregs & 0x1) && (ARM_INSN_REG_RN(insn) == i))
- continue;
- if ((uregs & 0x2) && (ARM_INSN_REG_RD(insn) == i))
- continue;
- if ((uregs & 0x4) && (ARM_INSN_REG_RS(insn) == i))
- continue;
- if ((uregs & 0x8) && (ARM_INSN_REG_RM(insn) == i))
- continue;
- break;
- }
- }
-
- if (i == 13) {
- DBPRINTF("there are no free register %x in insn %lx!",
- uregs, insn);
- return -EINVAL;
- }
- DBPRINTF("prep_pc_dep_insn_execbuf: using R%d, changing regs %x",
- i, uregs);
-
- /* set register to save */
- ARM_INSN_REG_SET_RD(insns[0], i);
- /* set register to load address to */
- ARM_INSN_REG_SET_RD(insns[1], i);
- /* set instruction to execute and patch it */
- if (uregs & 0x10) {
- ARM_INSN_REG_CLEAR_MR(insn, 15);
- ARM_INSN_REG_SET_MR(insn, i);
- } else {
- if ((uregs & 0x1) && (ARM_INSN_REG_RN(insn) == 15))
- ARM_INSN_REG_SET_RN(insn, i);
- if ((uregs & 0x2) && (ARM_INSN_REG_RD(insn) == 15))
- ARM_INSN_REG_SET_RD(insn, i);
- if ((uregs & 0x4) && (ARM_INSN_REG_RS(insn) == 15))
- ARM_INSN_REG_SET_RS(insn, i);
- if ((uregs & 0x8) && (ARM_INSN_REG_RM(insn) == 15))
- ARM_INSN_REG_SET_RM(insn, i);
- }
-
- insns[UPROBES_TRAMP_INSN_IDX] = insn;
- /* set register to restore */
- ARM_INSN_REG_SET_RD(insns[3], i);
-
- return 0;
-}
-
-static int arch_check_insn_arm(unsigned long insn)
-{
- /* check instructions that can change PC by nature */
- if (
- /* ARM_INSN_MATCH(UNDEF, insn) || */
- ARM_INSN_MATCH(AUNDEF, insn) ||
- ARM_INSN_MATCH(SWI, insn) ||
- ARM_INSN_MATCH(BREAK, insn) ||
- ARM_INSN_MATCH(BXJ, insn)) {
- goto bad_insn;
-#ifndef CONFIG_CPU_V7
- /* check instructions that can write result to PC */
- } else if ((ARM_INSN_MATCH(DPIS, insn) ||
- ARM_INSN_MATCH(DPRS, insn) ||
- ARM_INSN_MATCH(DPI, insn) ||
- ARM_INSN_MATCH(LIO, insn) ||
- ARM_INSN_MATCH(LRO, insn)) &&
- (ARM_INSN_REG_RD(insn) == 15)) {
- goto bad_insn;
-#endif /* CONFIG_CPU_V7 */
- /* check special instruction loads store multiple registers */
- } else if ((ARM_INSN_MATCH(LM, insn) || ARM_INSN_MATCH(SM, insn)) &&
- /* store PC or load to PC */
- (ARM_INSN_REG_MR(insn, 15) ||
- /* store/load with PC update */
- ((ARM_INSN_REG_RN(insn) == 15) && (insn & 0x200000)))) {
- goto bad_insn;
- }
-
- return 0;
-
-bad_insn:
- return -EFAULT;
-}
-
-static int make_branch_tarmpoline(unsigned long addr, unsigned long insn,
- unsigned long *tramp)
-{
- int ok = 0;
-
- /* B */
- if (ARM_INSN_MATCH(B, insn) &&
- !ARM_INSN_MATCH(BLX1, insn)) {
- /* B check can be false positive on BLX1 instruction */
- memcpy(tramp, b_cond_insn_execbuf, KPROBES_TRAMP_LEN);
- tramp[KPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
- tramp[0] |= insn & 0xf0000000;
- tramp[6] = get_addr_b(insn, addr);
- tramp[7] = addr + 4;
- ok = 1;
- /* BX, BLX (Rm) */
- } else if (ARM_INSN_MATCH(BX, insn) ||
- ARM_INSN_MATCH(BLX2, insn)) {
- memcpy(tramp, b_r_insn_execbuf, KPROBES_TRAMP_LEN);
- tramp[0] = insn;
- tramp[KPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
- tramp[7] = addr + 4;
- ok = 1;
- /* BL, BLX (Off) */
- } else if (ARM_INSN_MATCH(BLX1, insn)) {
- memcpy(tramp, blx_off_insn_execbuf, KPROBES_TRAMP_LEN);
- tramp[0] |= 0xe0000000;
- tramp[1] |= 0xe0000000;
- tramp[KPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
- tramp[6] = get_addr_b(insn, addr) +
- 2 * (insn & 01000000) + 1; /* jump to thumb */
- tramp[7] = addr + 4;
- ok = 1;
- /* BL */
- } else if (ARM_INSN_MATCH(BL, insn)) {
- memcpy(tramp, blx_off_insn_execbuf, KPROBES_TRAMP_LEN);
- tramp[0] |= insn & 0xf0000000;
- tramp[1] |= insn & 0xf0000000;
- tramp[KPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
- tramp[6] = get_addr_b(insn, addr);
- tramp[7] = addr + 4;
- ok = 1;
- }
-
- return ok;
-}
-
-/**
- * @brief Creates ARM trampoline.
- *
- * @param addr Probe address.
- * @param insn Instuction at this address.
- * @param tramp Pointer to memory for trampoline.
- * @return 0 on success, error code on error.
- */
-int arch_make_trampoline_arm(unsigned long addr, unsigned long insn,
- unsigned long *tramp)
-{
- int ret, uregs, pc_dep;
-
- if (addr & 0x03) {
- printk(KERN_INFO "Error in %s at %d: attempt to register uprobe "
- "at an unaligned address\n", __FILE__, __LINE__);
- return -EINVAL;
- }
-
- ret = arch_check_insn_arm(insn);
- if (ret)
- return ret;
-
- if (make_branch_tarmpoline(addr, insn, tramp))
- return 0;
-
- uregs = pc_dep = 0;
- /* Rm */
- if (ARM_INSN_MATCH(CLZ, insn)) {
- uregs = 0xa;
- if (ARM_INSN_REG_RM(insn) == 15)
- pc_dep = 1;
- /* Rn, Rm ,Rd */
- } else if (ARM_INSN_MATCH(DPIS, insn) || ARM_INSN_MATCH(LRO, insn) ||
- ARM_INSN_MATCH(SRO, insn)) {
- uregs = 0xb;
- if ((ARM_INSN_REG_RN(insn) == 15) ||
- (ARM_INSN_REG_RM(insn) == 15) ||
- (ARM_INSN_MATCH(SRO, insn) &&
- (ARM_INSN_REG_RD(insn) == 15))) {
- pc_dep = 1;
- }
- /* Rn ,Rd */
- } else if (ARM_INSN_MATCH(DPI, insn) || ARM_INSN_MATCH(LIO, insn) ||
- ARM_INSN_MATCH(SIO, insn)) {
- uregs = 0x3;
- if ((ARM_INSN_REG_RN(insn) == 15) ||
- (ARM_INSN_MATCH(SIO, insn) &&
- (ARM_INSN_REG_RD(insn) == 15))) {
- pc_dep = 1;
- }
- /* Rn, Rm, Rs */
- } else if (ARM_INSN_MATCH(DPRS, insn)) {
- uregs = 0xd;
- if ((ARM_INSN_REG_RN(insn) == 15) ||
- (ARM_INSN_REG_RM(insn) == 15) ||
- (ARM_INSN_REG_RS(insn) == 15)) {
- pc_dep = 1;
- }
- /* register list */
- } else if (ARM_INSN_MATCH(SM, insn)) {
- uregs = 0x10;
- if (ARM_INSN_REG_MR(insn, 15))
- pc_dep = 1;
- }
-
- /* check instructions that can write result to SP and uses PC */
- if (pc_dep && (ARM_INSN_REG_RD(insn) == 13)) {
- printk(KERN_INFO "Error in %s at %d: instruction check failed (arm)\n",
- __FILE__, __LINE__);
- return -EFAULT;
- }
-
- if (unlikely(uregs && pc_dep)) {
- memcpy(tramp, pc_dep_insn_execbuf, KPROBES_TRAMP_LEN);
- if (prep_pc_dep_insn_execbuf(tramp, insn, uregs) != 0) {
- printk(KERN_INFO "Error in %s at %d: failed "
- "to prepare exec buffer for insn %lx!",
- __FILE__, __LINE__, insn);
- return -EINVAL;
- }
-
- tramp[6] = addr + 8;
- } else {
- memcpy(tramp, gen_insn_execbuf, KPROBES_TRAMP_LEN);
- tramp[KPROBES_TRAMP_INSN_IDX] = insn;
- }
-
- /* TODO: remove for kprobe */
- tramp[KPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
- tramp[7] = addr + 4;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(arch_make_trampoline_arm);
-
-/**
- * @brief Creates trampoline for kprobe.
- *
- * @param p Pointer to kprobe.
- * @param sm Pointer to slot manager
- * @return 0 on success, error code on error.
- */
-int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm)
-{
- unsigned long addr = (unsigned long)p->addr;
- unsigned long insn = p->opcode = *p->addr;
- unsigned long *tramp;
- int ret;
-
- tramp = swap_slot_alloc(sm);
- if (tramp == NULL)
- return -ENOMEM;
-
- ret = arch_make_trampoline_arm(addr, insn, tramp);
- if (ret) {
- swap_slot_free(sm, tramp);
- return ret;
- }
-
- flush_icache_range((unsigned long)tramp,
- (unsigned long)tramp + KPROBES_TRAMP_LEN);
-
- p->ainsn.insn = tramp;
-
- return 0;
-}
-
-/**
- * @brief Prepares singlestep for current CPU.
- *
- * @param p Pointer to kprobe.
- * @param regs Pointer to CPU registers data.
- * @return Void.
- */
-void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
-{
- int cpu = smp_processor_id();
-
- if (p->ss_addr[cpu]) {
- regs->ARM_pc = (unsigned long)p->ss_addr[cpu];
- p->ss_addr[cpu] = NULL;
- } else {
- regs->ARM_pc = (unsigned long)p->ainsn.insn;
- }
-}
-EXPORT_SYMBOL_GPL(prepare_singlestep);
-
-/**
- * @brief Saves previous kprobe.
- *
- * @param kcb Pointer to kprobe_ctlblk struct whereto save current kprobe.
- * @param p_run Pointer to kprobe.
- * @return Void.
- */
-void save_previous_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p_run)
-{
- kcb->prev_kprobe.kp = swap_kprobe_running();
- kcb->prev_kprobe.status = kcb->kprobe_status;
-}
-
-/**
- * @brief Restores previous kprobe.
- *
- * @param kcb Pointer to kprobe_ctlblk which contains previous kprobe.
- * @return Void.
- */
-void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
-{
- __get_cpu_var(swap_current_kprobe) = kcb->prev_kprobe.kp;
- kcb->kprobe_status = kcb->prev_kprobe.status;
-}
-
-/**
- * @brief Sets currently running kprobe.
- *
- * @param p Pointer to currently running kprobe.
- * @param regs Pointer to CPU registers data.
- * @param kcb Pointer to kprobe_ctlblk.
- * @return Void.
- */
-void set_current_kprobe(struct kprobe *p,
- struct pt_regs *regs,
- struct kprobe_ctlblk *kcb)
-{
- __get_cpu_var(swap_current_kprobe) = p;
- DBPRINTF("set_current_kprobe: p=%p addr=%p\n", p, p->addr);
-}
-
-static int kprobe_handler(struct pt_regs *regs)
-{
- struct kprobe *p, *cur;
- struct kprobe_ctlblk *kcb;
-
- kcb = swap_get_kprobe_ctlblk();
- cur = swap_kprobe_running();
- p = swap_get_kprobe((void *)regs->ARM_pc);
-
- if (p) {
- if (cur) {
- /* Kprobe is pending, so we're recursing. */
- switch (kcb->kprobe_status) {
- case KPROBE_HIT_ACTIVE:
- case KPROBE_HIT_SSDONE:
- /* A pre- or post-handler probe got us here. */
- swap_kprobes_inc_nmissed_count(p);
- save_previous_kprobe(kcb, NULL);
- set_current_kprobe(p, 0, 0);
- kcb->kprobe_status = KPROBE_REENTER;
- prepare_singlestep(p, regs);
- restore_previous_kprobe(kcb);
- break;
- default:
- /* impossible cases */
- BUG();
- }
- } else {
- set_current_kprobe(p, 0, 0);
- kcb->kprobe_status = KPROBE_HIT_ACTIVE;
-
- if (!p->pre_handler || !p->pre_handler(p, regs)) {
- kcb->kprobe_status = KPROBE_HIT_SS;
- prepare_singlestep(p, regs);
- swap_reset_current_kprobe();
- }
- }
- } else {
- goto no_kprobe;
- }
-
- return 0;
-
-no_kprobe:
- printk(KERN_INFO "no_kprobe: Not one of ours: let kernel handle it %p\n",
- (unsigned long *)regs->ARM_pc);
- return 1;
-}
-
-/**
- * @brief Trap handler.
- *
- * @param regs Pointer to CPU register data.
- * @param instr Instruction.
- * @return kprobe_handler result.
- */
-int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
-{
- int ret;
- unsigned long flags;
-
- local_irq_save(flags);
- preempt_disable();
- ret = kprobe_handler(regs);
- swap_preempt_enable_no_resched();
- local_irq_restore(flags);
-
- return ret;
-}
-
-/**
- * @brief Probe pre handler.
- *
- * @param p Pointer to fired kprobe.
- * @param regs Pointer to CPU registers data.
- * @return 0.
- */
-int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct jprobe *jp = container_of(p, struct jprobe, kp);
- kprobe_pre_entry_handler_t pre_entry =
- (kprobe_pre_entry_handler_t)jp->pre_entry;
- entry_point_t entry = (entry_point_t)jp->entry;
- pre_entry = (kprobe_pre_entry_handler_t)jp->pre_entry;
-
- if (pre_entry) {
- p->ss_addr[smp_processor_id()] = (void *)
- pre_entry(jp->priv_arg, regs);
- }
-
- if (entry) {
- entry(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
- regs->ARM_r3, regs->ARM_r4, regs->ARM_r5);
- } else {
- swap_jprobe_return();
- }
-
- return 0;
-}
-
-/**
- * @brief Jprobe return stub.
- *
- * @return Void.
- */
-void swap_jprobe_return(void)
-{
-}
-EXPORT_SYMBOL_GPL(swap_jprobe_return);
-
-/**
- * @brief Break handler stub.
- *
- * @param p Pointer to fired kprobe.
- * @param regs Pointer to CPU registers data.
- * @return 0.
- */
-int swap_longjmp_break_handler (struct kprobe *p, struct pt_regs *regs)
-{
- return 0;
-}
-EXPORT_SYMBOL_GPL(swap_longjmp_break_handler);
-
-#ifdef CONFIG_STRICT_MEMORY_RWX
-#include "memory_rwx.h"
-
-static void write_u32(unsigned long addr, unsigned long val)
-{
- mem_rwx_write_u32(addr, val);
-}
-#else /* CONFIG_STRICT_MEMORY_RWX */
-static void write_u32(unsigned long addr, unsigned long val)
-{
- *(long *)addr = val;
- flush_icache_range(addr, addr + sizeof(long));
-}
-#endif /* CONFIG_STRICT_MEMORY_RWX */
-
-/**
- * @brief Arms kprobe.
- *
- * @param p Pointer to target kprobe.
- * @return Void.
- */
-void swap_arch_arm_kprobe(struct kprobe *p)
-{
- write_u32((long)p->addr, BREAKPOINT_INSTRUCTION);
-}
-
-/**
- * @brief Disarms kprobe.
- *
- * @param p Pointer to target kprobe.
- * @return Void.
- */
-void swap_arch_disarm_kprobe(struct kprobe *p)
-{
- write_u32((long)p->addr, p->opcode);
-}
-
-/**
- * @brief Kretprobe trampoline. Provides jumping to probe handler.
- *
- * @return Void.
- */
-void __naked swap_kretprobe_trampoline(void)
-{
- __asm__ __volatile__ (
- "stmdb sp!, {r0 - r11}\n"
- "mov r1, sp\n"
- "mov r0, #0\n"
- "bl trampoline_probe_handler\n"
- "mov lr, r0\n"
- "ldmia sp!, {r0 - r11}\n"
- "bx lr\n"
- : : : "memory");
-}
-
-/**
- * @brief Prepares kretprobes, saves ret address, makes function return to
- * trampoline.
- *
- * @param ri Pointer to kretprobe_instance.
- * @param regs Pointer to CPU registers data.
- * @return Void.
- */
-void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- unsigned long *ptr_ret_addr;
-
- /* for __switch_to probe */
- if ((unsigned long)ri->rp->kp.addr == sched_addr) {
- struct thread_info *tinfo = (struct thread_info *)regs->ARM_r2;
-
- ptr_ret_addr = (unsigned long *)&tinfo->cpu_context.pc;
- ri->sp = NULL;
- ri->task = tinfo->task;
- } else {
- ptr_ret_addr = (unsigned long *)®s->ARM_lr;
- ri->sp = (unsigned long *)regs->ARM_sp;
- }
-
- /* Save the return address */
- ri->ret_addr = (unsigned long *)*ptr_ret_addr;
-
- /* Replace the return addr with trampoline addr */
- *ptr_ret_addr = (unsigned long)&swap_kretprobe_trampoline;
-}
-
-
-
-
-
-/*
- ******************************************************************************
- * kjumper *
- ******************************************************************************
- */
-struct kj_cb_data {
- unsigned long ret_addr;
-
- struct pt_regs regs;
-
- jumper_cb_t cb;
- char data[0];
-};
-
-static struct kj_cb_data * __used kjump_handler(struct kj_cb_data *data)
-{
- /* call callback */
- data->cb(data->data);
-
- return data;
-}
-
-/**
- * @brief Trampoline for kjump kprobes.
- *
- * @return Void.
- */
-void kjump_trampoline(void);
-__asm(
- "kjump_trampoline:\n"
-
- "mov r0, r10\n"
- "bl kjump_handler\n"
- "nop\n" /* for kjump_kprobe */
-);
-
-/**
- * @brief Registers callback for kjump probes.
- *
- * @param regs Pointer to CPU registers data.
- * @param cb Kjump probe callback of jumper_cb_t type.
- * @param data Pointer to data that should be saved in kj_cb_data.
- * @param size Size of the data.
- * @return 0.
- */
-int set_kjump_cb(struct pt_regs *regs, jumper_cb_t cb, void *data, size_t size)
-{
- struct kprobe *p;
- struct kj_cb_data *cb_data;
-
- cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
- if (cb_data == NULL)
- return -ENOMEM;
-
- /* save data */
- if (size)
- memcpy(cb_data->data, data, size);
-
- p = swap_kprobe_running();
- p->ss_addr[smp_processor_id()] = (kprobe_opcode_t *)&kjump_trampoline;
-
- cb_data->ret_addr = (unsigned long)p->ainsn.insn;
- cb_data->cb = cb;
-
- /* save regs */
- memcpy(&cb_data->regs, regs, sizeof(*regs));
-
- /* save cb_data to r10 */
- regs->ARM_r10 = (long)cb_data;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(set_kjump_cb);
-
-static int kjump_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct kj_cb_data *data = (struct kj_cb_data *)regs->ARM_r0;
-
- /* restore regs */
- memcpy(regs, &data->regs, sizeof(*regs));
- p->ss_addr[smp_processor_id()] = (void *)data->ret_addr;
-
- /* FIXME: potential memory leak, when process kill */
- kfree(data);
-
- return 0;
-}
-
-static struct kprobe kjump_kprobe = {
- .pre_handler = kjump_pre_handler,
- .addr = (unsigned long *)&kjump_trampoline + 2, /* nop */
-};
-
-static int kjump_init(void)
-{
- int ret;
-
- ret = swap_register_kprobe(&kjump_kprobe);
- if (ret)
- printk(KERN_INFO "ERROR: kjump_init(), ret=%d\n", ret);
-
- return ret;
-}
-
-static void kjump_exit(void)
-{
- swap_unregister_kprobe(&kjump_kprobe);
-}
-
-
-
-
-
-/*
- ******************************************************************************
- * jumper *
- ******************************************************************************
- */
-struct cb_data {
- unsigned long ret_addr;
- unsigned long r0;
-
- jumper_cb_t cb;
- char data[0];
-};
-
-static unsigned long __used get_r0(struct cb_data *data)
-{
- return data->r0;
-}
-
-static unsigned long __used jump_handler(struct cb_data *data)
-{
- unsigned long ret_addr = data->ret_addr;
-
- /* call callback */
- data->cb(data->data);
-
- /* FIXME: potential memory leak, when process kill */
- kfree(data);
-
- return ret_addr;
-}
-
-/* FIXME: restore condition flags */
-
-/**
- * @brief Jumper trampoline.
- *
- * @return Void.
- */
-void jump_trampoline(void);
-__asm(
- "jump_trampoline:\n"
-
- "push {r0 - r12}\n"
- "mov r1, r0\n" /* data --> r1 */
- "bl get_r0\n"
- "str r0, [sp]\n" /* restore r0 */
- "mov r0, r1\n" /* data --> r0 */
- "bl jump_handler\n"
- "mov lr, r0\n"
- "pop {r0 - r12}\n"
- "bx lr\n"
-);
-
-/**
- * @brief Get jumper address.
- *
- * @return Jumper address.
- */
-unsigned long get_jump_addr(void)
-{
- return (unsigned long)&jump_trampoline;
-}
-EXPORT_SYMBOL_GPL(get_jump_addr);
-
-/**
- * @brief Set jumper probe callback.
- *
- * @param ret_addr Jumper probe return address.
- * @param regs Pointer to CPU registers data.
- * @param cb Jumper callback of jumper_cb_t type.
- * @param data Data that should be stored in cb_data.
- * @param size Size of the data.
- * @return 0.
- */
-int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
- jumper_cb_t cb, void *data, size_t size)
-{
- struct cb_data *cb_data;
-
- cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
- if (cb_data == NULL)
- return -ENOMEM;
-
- /* save data */
- if (size)
- memcpy(cb_data->data, data, size);
-
- /* save info for restore */
- cb_data->ret_addr = ret_addr;
- cb_data->cb = cb;
- cb_data->r0 = regs->ARM_r0;
-
- /* save cb_data to r0 */
- regs->ARM_r0 = (long)cb_data;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(set_jump_cb);
-
-
-
-
-/**
- * @brief Registers hook on specified instruction.
- *
- * @param hook Pointer to struct undef_hook.
- * @return Void.
- */
-void swap_register_undef_hook(struct undef_hook *hook)
-{
- __swap_register_undef_hook(hook);
-}
-EXPORT_SYMBOL_GPL(swap_register_undef_hook);
-
-/**
- * @brief Unregisters hook.
- *
- * @param hook Pointer to struct undef_hook.
- * @return Void.
- */
-void swap_unregister_undef_hook(struct undef_hook *hook)
-{
- __swap_unregister_undef_hook(hook);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_undef_hook);
-
-/* kernel probes hook */
-static struct undef_hook undef_ho_k = {
- .instr_mask = 0xffffffff,
- .instr_val = BREAKPOINT_INSTRUCTION,
- .cpsr_mask = MODE_MASK,
- .cpsr_val = SVC_MODE,
- .fn = kprobe_trap_handler
-};
-
-/**
- * @brief Arch-dependend module deps initialization stub.
- *
- * @return 0.
- */
-int arch_init_module_deps(void)
-{
- const char *sym;
-#ifdef CONFIG_STRICT_MEMORY_RWX
- int ret;
-
- ret = mem_rwx_once();
- if (ret)
- return ret;
-#endif /* CONFIG_STRICT_MEMORY_RWX */
-
- sym = "register_undef_hook";
- __swap_register_undef_hook = (void *)swap_ksyms(sym);
- if (__swap_register_undef_hook == NULL)
- goto not_found;
-
- sym = "unregister_undef_hook";
- __swap_unregister_undef_hook = (void *)swap_ksyms(sym);
- if (__swap_unregister_undef_hook == NULL)
- goto not_found;
-
- return 0;
-
-not_found:
- printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
- return -ESRCH;
-}
-
-/**
- * @brief Initializes kprobes module for ARM arch.
- *
- * @return 0 on success, error code on error.
- */
-int swap_arch_init_kprobes(void)
-{
- int ret;
-
- swap_register_undef_hook(&undef_ho_k);
-
- ret = kjump_init();
- if (ret) {
- swap_unregister_undef_hook(&undef_ho_k);
- return ret;
- }
-
- return 0;
-}
-
-/**
- * @brief Uninitializes kprobe module.
- *
- * @return Void.
- */
-void swap_arch_exit_kprobes(void)
-{
- kjump_exit();
- swap_unregister_undef_hook(&undef_ho_k);
-}
-
-/* export symbol for trampoline_arm.h */
-EXPORT_SYMBOL_GPL(gen_insn_execbuf);
-EXPORT_SYMBOL_GPL(pc_dep_insn_execbuf);
-EXPORT_SYMBOL_GPL(b_r_insn_execbuf);
-EXPORT_SYMBOL_GPL(b_cond_insn_execbuf);
-EXPORT_SYMBOL_GPL(blx_off_insn_execbuf);
+++ /dev/null
-/**
- * @file kprobe/arch/asm-arm/swap_kprobes.h
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>:
- * initial implementation for ARM/MIPS
- * @author Alexey Gerenkov <a.gerenkov@samsung.com>:
- * User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>:
- * redesign module for separating core and arch parts
- * @author Alexander Shirshikov <a.shirshikov@samsung.com>:
- * initial implementation for Thumb
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * ARM arch-dependent kprobes interface declaration.
- */
-
-
-#ifndef _SWAP_ASM_ARM_KPROBES_H
-#define _SWAP_ASM_ARM_KPROBES_H
-
-#include <linux/sched.h>
-#include <linux/compiler.h>
-
-typedef unsigned long kprobe_opcode_t;
-
-#ifdef CONFIG_CPU_S3C2443
-/** Breakpoint instruction */
-#define BREAKPOINT_INSTRUCTION 0xe1200070
-#else
-/** Breakpoint instruction */
-#define BREAKPOINT_INSTRUCTION 0xffffdeff
-#endif /* CONFIG_CPU_S3C2443 */
-
-#ifndef KPROBES_RET_PROBE_TRAMP
-
-#ifdef CONFIG_CPU_S3C2443
-/** Undefined instruction */
-#define UNDEF_INSTRUCTION 0xe1200071
-#else
-/** Undefined instruction */
-#define UNDEF_INSTRUCTION 0xfffffffe
-#endif /* CONFIG_CPU_S3C2443 */
-
-#endif /* KPROBES_RET_PROBE_TRAMP */
-
-/** Maximum insn size */
-#define MAX_INSN_SIZE 1
-
-/** Uprobes trampoline length */
-#define UPROBES_TRAMP_LEN (9 * 4)
-/** Uprobes trampoline insn idx */
-#define UPROBES_TRAMP_INSN_IDX 2
-/** Uprobes trampoline ss break idx */
-#define UPROBES_TRAMP_SS_BREAK_IDX 4
-/** Uprobes trampoline ret break idx */
-#define UPROBES_TRAMP_RET_BREAK_IDX 5
-/** Kprobes trampoline length */
-#define KPROBES_TRAMP_LEN (9 * 4)
-/** Kprobes trampoline insn idx */
-#define KPROBES_TRAMP_INSN_IDX UPROBES_TRAMP_INSN_IDX
-/** Kprobes trampoline ss break idx */
-#define KPROBES_TRAMP_SS_BREAK_IDX UPROBES_TRAMP_SS_BREAK_IDX
-
-/* TODO: remove (not needed for kprobe) */
-#define KPROBES_TRAMP_RET_BREAK_IDX UPROBES_TRAMP_RET_BREAK_IDX
-
-/** User register offset */
-#define UREGS_OFFSET 8
-
-/**
- * @struct prev_kprobe
- * @brief Stores previous kprobe.
- * @var prev_kprobe::kp
- * Pointer to kprobe struct.
- * @var prev_kprobe::status
- * Kprobe status.
- */
-struct prev_kprobe {
- struct kprobe *kp;
- unsigned long status;
-};
-
-/**
- * @brief Gets task pc.
- *
- * @param p Pointer to task_struct
- * @return Value in pc.
- */
-static inline unsigned long arch_get_task_pc(struct task_struct *p)
-{
- return task_thread_info(p)->cpu_context.pc;
-}
-
-/**
- * @brief Sets task pc.
- *
- * @param p Pointer to task_struct.
- * @param val Value that should be set.
- * @return Void.
- */
-static inline void arch_set_task_pc(struct task_struct *p, unsigned long val)
-{
- task_thread_info(p)->cpu_context.pc = val;
-}
-
-/**
- * @brief Gets syscall registers.
- *
- * @param sp Pointer to stack.
- * @return Pointer to CPU regs data.
- */
-static inline struct pt_regs *swap_get_syscall_uregs(unsigned long sp)
-{
- return (struct pt_regs *)(sp + UREGS_OFFSET);
-}
-
-/**
- * @brief Gets stack pointer.
- *
- * @param regs Pointer to CPU registers data.
- * @return Stack address.
- */
-static inline unsigned long swap_get_stack_ptr(struct pt_regs *regs)
-{
- return regs->ARM_sp;
-}
-
-/**
- * @brief Sets stack pointer.
- *
- * @param regs Pointer to CPU registers data.
- * @param sp New stack pointer value.
- * @return Void
- */
-static inline void swap_set_stack_ptr(struct pt_regs *regs, unsigned long sp)
-{
- regs->ARM_sp = sp;
-}
-
-/**
- * @brief Gets instruction pointer.
- *
- * @param regs Pointer to CPU registers data.
- * @return Pointer to pc.
- */
-static inline unsigned long swap_get_instr_ptr(struct pt_regs *regs)
-{
- return regs->ARM_pc;
-}
-
-/**
- * @brief Sets instruction pointer.
- *
- * @param regs Pointer to CPU registers data.
- * @param val Address that should be stored in pc.
- * @return Void.
- */
-static inline void swap_set_instr_ptr(struct pt_regs *regs, unsigned long val)
-{
- regs->ARM_pc = val;
-}
-
-/**
- * @brief Gets return address.
- *
- * @param regs Pointer to CPU registers data.
- * @return Return address.
- */
-static inline unsigned long swap_get_ret_addr(struct pt_regs *regs)
-{
- return regs->ARM_lr;
-}
-
-/**
- * @brief Sets return address.
- *
- * @param regs Pointer to CPU registers data.
- * @param val New return address.
- * @return Void.
- */
-static inline void swap_set_ret_addr(struct pt_regs *regs, unsigned long val)
-{
- regs->ARM_lr = val;
-}
-
-/**
- * @brief Gets specified argument.
- *
- * @param regs Pointer to CPU registers data.
- * @param num Number of the argument.
- * @return Argument value.
- */
-static inline unsigned long swap_get_arg(struct pt_regs *regs, int num)
-{
- return regs->uregs[num];
-}
-
-/**
- * @brief Sets specified argument.
- *
- * @param regs Pointer to CPU registers data.
- * @param num Number of the argument.
- * @param val New argument value.
- * @return Void.
- */
-static inline void swap_set_arg(struct pt_regs *regs, int num,
- unsigned long val)
-{
- regs->uregs[num] = val;
-}
-
-/* undefined */
-#define MASK_ARM_INSN_UNDEF 0x0FF00000
-#define PTRN_ARM_INSN_UNDEF 0x03000000
-
-#define MASK_THUMB_INSN_UNDEF 0xFE00
-#define PTRN_THUMB_INSN_UNDEF 0xDE00
-
-/* architecturally undefined */
-#define MASK_ARM_INSN_AUNDEF 0x0FF000F0
-#define PTRN_ARM_INSN_AUNDEF 0x07F000F0
-
-/* branches */
-#define MASK_ARM_INSN_B 0x0F000000
-#define PTRN_ARM_INSN_B 0x0A000000
-
-#define MASK_THUMB_INSN_B1 0xF000
-#define PTRN_THUMB_INSN_B1 0xD000 /* b<cond> label */
-
-#define MASK_THUMB_INSN_B2 0xF800
-#define PTRN_THUMB_INSN_B2 0xE000 /* b label */
-
-#define MASK_THUMB_INSN_CBZ 0xF500
-#define PTRN_THUMB_INSN_CBZ 0xB100 /* CBZ/CBNZ */
-
-#define MASK_THUMB2_INSN_B1 0xD000F800
-#define PTRN_THUMB2_INSN_B1 0x8000F000
-
-#define MASK_THUMB2_INSN_B2 0xD000F800
-#define PTRN_THUMB2_INSN_B2 0x9000F000
-
-#define MASK_ARM_INSN_BL 0x0F000000
-#define PTRN_ARM_INSN_BL 0x0B000000
-
-/* #define MASK_THUMB_INSN_BL 0xF800 */
-/* #define PTRN_THUMB_INSN_BL 0xF000 shared between BL and BLX */
-/* #define PTRN_THUMB_INSN_BL 0xF800 */
-
-#define MASK_THUMB2_INSN_BL 0xD000F800
-#define PTRN_THUMB2_INSN_BL 0xD000F000 /* bl imm swapped */
-
-#define MASK_ARM_INSN_BLX1 0xFE000000
-#define PTRN_ARM_INSN_BLX1 0xFA000000
-
-/* #define MASK_THUMB_INSN_BLX1 0xF800 */
-/* #define PTRN_THUMB_INSN_BLX1 0xF000 */
-
-#define MASK_THUMB2_INSN_BLX1 0xD001F800
-#define PTRN_THUMB2_INSN_BLX1 0xC000F000
-
-#define MASK_ARM_INSN_BLX2 0x0FF000F0
-#define PTRN_ARM_INSN_BLX2 0x01200030
-
-#define MASK_THUMB_INSN_BLX2 0xFF80 /* blx reg */
-#define PTRN_THUMB_INSN_BLX2 0x4780
-
-#define MASK_ARM_INSN_BX 0x0FF000F0
-#define PTRN_ARM_INSN_BX 0x01200010
-
-#define MASK_THUMB_INSN_BX 0xFF80
-#define PTRN_THUMB_INSN_BX 0x4700
-
-#define MASK_ARM_INSN_BXJ 0x0FF000F0
-#define PTRN_ARM_INSN_BXJ 0x01200020
-
-#define MASK_THUMB2_INSN_BXJ 0xD000FFF0
-#define PTRN_THUMB2_INSN_BXJ 0x8000F3C0
-
-
-/* software interrupts */
-#define MASK_ARM_INSN_SWI 0x0F000000
-#define PTRN_ARM_INSN_SWI 0x0F000000
-
-#define MASK_THUMB_INSN_SWI 0xFF00
-#define PTRN_THUMB_INSN_SWI 0xDF00
-
-/* break */
-#define MASK_ARM_INSN_BREAK 0xFFF000F0
-#define PTRN_ARM_INSN_BREAK 0xE1200070
-/* A8-56 ARM DDI 046B if cond != ‘1110’ then UNPREDICTABLE; */
-
-#define MASK_THUMB_INSN_BREAK 0xFF00
-#define PTRN_THUMB_INSN_BREAK 0xBE00
-
-/* CLZ */
-#define MASK_ARM_INSN_CLZ 0x0FFF0FF0
-#define PTRN_ARM_INSN_CLZ 0x016F0F10
-
-/* Data processing immediate shift */
-#define MASK_ARM_INSN_DPIS 0x0E000010
-#define PTRN_ARM_INSN_DPIS 0x00000000
-/* Data processing register shift */
-#define MASK_ARM_INSN_DPRS 0x0E000090
-#define PTRN_ARM_INSN_DPRS 0x00000010
-
-#define MASK_THUMB2_INSN_DPRS 0xFFE00000
-#define PTRN_THUMB2_INSN_DPRS 0xEA000000
-
-/* Data processing immediate */
-#define MASK_ARM_INSN_DPI 0x0E000000
-#define PTRN_ARM_INSN_DPI 0x02000000
-
-#define MASK_THUMB_INSN_DP 0xFC00
-#define PTRN_THUMB_INSN_DP 0x4000
-
-#define MASK_THUMB_INSN_APC 0xF800
-#define PTRN_THUMB_INSN_APC 0xA000 /* ADD Rd, [PC, #<imm8> * 4] */
-
-#define MASK_THUMB2_INSN_DPI 0xFBE08000
-/* #define PTRN_THUMB2_INSN_DPI 0xF0000000 */
-/* A6-19 ARM DDI 0406B */
-#define PTRN_THUMB2_INSN_DPI 0xF2000000
-/* A6-19 ARM DDI 0406B */
-
-#define MASK_THUMB_INSN_MOV3 0xFF00
-#define PTRN_THUMB_INSN_MOV3 0x4600 /* MOV Rd, PC */
-
-#define MASK_THUMB2_INSN_RSBW 0x8000fbe0
-#define PTRN_THUMB2_INSN_RSBW 0x0000f1c0 /* RSB{S}.W Rd,Rn,#<const> */
-
-#define MASK_THUMB2_INSN_RORW 0xf0f0ffe0
-#define PTRN_THUMB2_INSN_RORW 0xf000fa60 /* ROR{S}.W Rd, Rn, Rm */
-
-#define MASK_THUMB2_INSN_ROR 0x0030ffef
-#define PTRN_THUMB2_INSN_ROR 0x0030ea4f /* ROR{S} Rd, Rm, #<imm> */
-
-#define MASK_THUMB2_INSN_LSLW1 0xf0f0ffe0
-#define PTRN_THUMB2_INSN_LSLW1 0xf000fa00 /* LSL{S}.W Rd, Rn, Rm */
-
-#define MASK_THUMB2_INSN_LSLW2 0x0030ffef
-#define PTRN_THUMB2_INSN_LSLW2 0x0000ea4f /* LSL{S}.W Rd, Rm, #<imm5>*/
-
-#define MASK_THUMB2_INSN_LSRW1 0xf0f0ffe0
-#define PTRN_THUMB2_INSN_LSRW1 0xf000fa20 /* LSR{S}.W Rd, Rn, Rm */
-
-#define MASK_THUMB2_INSN_LSRW2 0x0030ffef
-#define PTRN_THUMB2_INSN_LSRW2 0x0010ea4f /* LSR{S}.W Rd, Rm, #<imm5> */
-
-#define MASK_THUMB2_INSN_TEQ1 0x8f00fbf0
-#define PTRN_THUMB2_INSN_TEQ1 0x0f00f090 /* TEQ Rn, #<const> */
-
-#define MASK_THUMB2_INSN_TEQ2 0x0f00fff0
-#define PTRN_THUMB2_INSN_TEQ2 0x0f00ea90 /* TEQ Rn, Rm{,<shift>} */
-
-#define MASK_THUMB2_INSN_TST1 0x8f00fbf0
-#define PTRN_THUMB2_INSN_TST1 0x0f00f010 /* TST Rn, #<const> */
-
-#define MASK_THUMB2_INSN_TST2 0x0f00fff0
-#define PTRN_THUMB2_INSN_TST2 0x0f00ea10 /* TST Rn, Rm{,<shift>} */
-
-
-/* Load immediate offset */
-#define MASK_ARM_INSN_LIO 0x0E100000
-#define PTRN_ARM_INSN_LIO 0x04100000
-
-#define MASK_THUMB_INSN_LIO1 0xF800
-#define PTRN_THUMB_INSN_LIO1 0x6800 /* LDR */
-
-#define MASK_THUMB_INSN_LIO2 MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_LIO2 0x7800 /* LDRB */
-
-#define MASK_THUMB_INSN_LIO3 MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_LIO3 0x8800 /* LDRH */
-
-#define MASK_THUMB_INSN_LIO4 MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_LIO4 0x9800 /* LDR SP relative */
-
-#define MASK_THUMB2_INSN_LDRW 0x0000fff0
-#define PTRN_THUMB2_INSN_LDRW 0x0000f850 /* LDR.W Rt, [Rn, #-<imm12>] */
-
-#define MASK_THUMB2_INSN_LDRW1 MASK_THUMB2_INSN_LDRW
-#define PTRN_THUMB2_INSN_LDRW1 0x0000f8d0 /* LDR.W Rt, [Rn, #<imm12>] */
-
-#define MASK_THUMB2_INSN_LDRBW MASK_THUMB2_INSN_LDRW
-#define PTRN_THUMB2_INSN_LDRBW 0x0000f810 /* LDRB.W Rt, [Rn, #-<imm8>] */
-
-#define MASK_THUMB2_INSN_LDRBW1 MASK_THUMB2_INSN_LDRW
-#define PTRN_THUMB2_INSN_LDRBW1 0x0000f890 /* LDRB.W Rt, [Rn, #<imm12>] */
-
-#define MASK_THUMB2_INSN_LDRHW MASK_THUMB2_INSN_LDRW
-#define PTRN_THUMB2_INSN_LDRHW 0x0000f830 /* LDRH.W Rt, [Rn, #-<imm8>] */
-
-#define MASK_THUMB2_INSN_LDRHW1 MASK_THUMB2_INSN_LDRW
-#define PTRN_THUMB2_INSN_LDRHW1 0x0000f8b0 /* LDRH.W Rt, [Rn, #<imm12>] */
-
-#define MASK_THUMB2_INSN_LDRD 0x0000fed0
-#define PTRN_THUMB2_INSN_LDRD 0x0000e850 /* LDRD Rt, Rt2, [Rn, #-<imm8>] */
-
-#define MASK_THUMB2_INSN_LDRD1 MASK_THUMB2_INSN_LDRD
-#define PTRN_THUMB2_INSN_LDRD1 0x0000e8d0 /* LDRD Rt, Rt2, [Rn, #<imm8>] */
-
-#define MASK_THUMB2_INSN_LDRWL 0x0fc0fff0
-#define PTRN_THUMB2_INSN_LDRWL 0x0000f850 /* LDR.W Rt, [Rn,Rm,LSL #<imm2>] */
-
-#define MASK_THUMB2_INSN_LDREX 0x0f00ffff
-#define PTRN_THUMB2_INSN_LDREX 0x0f00e85f /* LDREX Rt, [PC, #<imm8>] */
-
-#define MASK_THUMB2_INSN_MUL 0xf0f0fff0
-#define PTRN_THUMB2_INSN_MUL 0xf000fb00 /* MUL Rd, Rn, Rm */
-
-#define MASK_THUMB2_INSN_DP 0x0000ff00
-#define PTRN_THUMB2_INSN_DP 0x0000eb00 /* ADD/SUB/SBC/...Rd,Rn,Rm{,<shift>} */
-
-
-
-
-/* Store immediate offset */
-#define MASK_ARM_INSN_SIO MASK_ARM_INSN_LIO
-#define PTRN_ARM_INSN_SIO 0x04000000
-
-#define MASK_THUMB_INSN_SIO1 MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_SIO1 0x6000 /* STR */
-
-#define MASK_THUMB_INSN_SIO2 MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_SIO2 0x7000 /* STRB */
-
-#define MASK_THUMB_INSN_SIO3 MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_SIO3 0x8000 /* STRH */
-
-#define MASK_THUMB_INSN_SIO4 MASK_THUMB_INSN_LIO1
-#define PTRN_THUMB_INSN_SIO4 0x9000 /* STR SP relative */
-
-#define MASK_THUMB2_INSN_STRW 0x0fc0fff0
-#define PTRN_THUMB2_INSN_STRW 0x0000f840 /* STR.W Rt,[Rn,Rm,{LSL #<imm2>}] */
-
-#define MASK_THUMB2_INSN_STRW1 0x0000fff0
-#define PTRN_THUMB2_INSN_STRW1 0x0000f8c0 /* STR.W Rt, [Rn, #imm12]
- * STR.W Rt, [PC, #imm12] shall be
- * skipped, because it hangs
- * on Tegra. WTF */
-
-#define MASK_THUMB2_INSN_STRHW MASK_THUMB2_INSN_STRW
-#define PTRN_THUMB2_INSN_STRHW 0x0000f820 /* STRH.W Rt,[Rn,Rm,{LSL #<imm2>}] */
-
-#define MASK_THUMB2_INSN_STRHW1 0x0000fff0
-#define PTRN_THUMB2_INSN_STRHW1 0x0000f8a0 /* STRH.W Rt, [Rn, #<imm12>] */
-
-#define MASK_THUMB2_INSN_STRHT 0x0f00fff0 /* strht r1, [pc, #imm] illegal
- * instruction on Tegra. WTF */
-#define PTRN_THUMB2_INSN_STRHT 0x0e00f820 /* STRHT Rt, [Rn, #<imm8>] */
-
-#define MASK_THUMB2_INSN_STRT 0x0f00fff0
-#define PTRN_THUMB2_INSN_STRT 0x0e00f840 /* STRT Rt, [Rn, #<imm8>] */
-
-#define MASK_THUMB2_INSN_STRBW MASK_THUMB2_INSN_STRW
-#define PTRN_THUMB2_INSN_STRBW 0x0000f800 /* STRB.W Rt,[Rn,Rm,{LSL #<imm2>}] */
-
-#define MASK_THUMB2_INSN_STRBW1 0x0000fff0
-#define PTRN_THUMB2_INSN_STRBW1 0x0000f880 /* STRB.W Rt, [Rn, #<imm12>]
- * STRB.W Rt, [PC, #imm12] shall be
- * skipped, because it hangs
- * on Tegra. WTF */
-
-#define MASK_THUMB2_INSN_STRBT 0x0f00fff0
-#define PTRN_THUMB2_INSN_STRBT 0x0e00f800 /* STRBT Rt, [Rn, #<imm8>}] */
-
-#define MASK_THUMB2_INSN_STRD 0x0000fe50
-/* STR{D,EX,EXB,EXH,EXD} Rt, Rt2, [Rn, #<imm8>] */
-#define PTRN_THUMB2_INSN_STRD 0x0000e840
-
-
-/* Load register offset */
-#define MASK_ARM_INSN_LRO 0x0E100010
-#define PTRN_ARM_INSN_LRO 0x06100000
-
-#define MASK_THUMB_INSN_LRO1 0xFE00
-#define PTRN_THUMB_INSN_LRO1 0x5600 /* LDRSB */
-
-#define MASK_THUMB_INSN_LRO2 MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_LRO2 0x5800 /* LDR */
-
-#define MASK_THUMB_INSN_LRO3 0xf800
-#define PTRN_THUMB_INSN_LRO3 0x4800 /* LDR Rd, [PC, #<imm8> * 4] */
-
-#define MASK_THUMB_INSN_LRO4 MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_LRO4 0x5A00 /* LDRH */
-
-#define MASK_THUMB_INSN_LRO5 MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_LRO5 0x5C00 /* LDRB */
-
-#define MASK_THUMB_INSN_LRO6 MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_LRO6 0x5E00 /* LDRSH */
-
-#define MASK_THUMB2_INSN_ADR 0x8000fa1f
-#define PTRN_THUMB2_INSN_ADR 0x0000f20f
-
-
-
-/* Store register offset */
-#define MASK_ARM_INSN_SRO MASK_ARM_INSN_LRO
-#define PTRN_ARM_INSN_SRO 0x06000000
-
-#define MASK_THUMB_INSN_SRO1 MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_SRO1 0x5000 /* STR */
-
-#define MASK_THUMB_INSN_SRO2 MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_SRO2 0x5200 /* STRH */
-
-#define MASK_THUMB_INSN_SRO3 MASK_THUMB_INSN_LRO1
-#define PTRN_THUMB_INSN_SRO3 0x5400 /* STRB */
-
-/* Load multiple */
-#define MASK_ARM_INSN_LM 0x0E100000
-#define PTRN_ARM_INSN_LM 0x08100000
-
-#define MASK_THUMB2_INSN_LDMIA 0x8000ffd0
-#define PTRN_THUMB2_INSN_LDMIA 0x8000e890 /* LDMIA(.W) Rn(!),{Rx-PC} */
-
-#define MASK_THUMB2_INSN_LDMDB 0x8000ffd0
-#define PTRN_THUMB2_INSN_LDMDB 0x8000e910 /* LDMDB(.W) Rn(!), {Rx-PC} */
-
-/* Store multiple */
-#define MASK_ARM_INSN_SM MASK_ARM_INSN_LM
-#define PTRN_ARM_INSN_SM 0x08000000
-
-
-/* Coprocessor load/store and double register transfers */
-#define MASK_ARM_INSN_CLS 0x0E000000
-#define PTRN_ARM_INSN_CLS 0x0C000000
-/* Coprocessor register transfers */
-#define MASK_ARM_INSN_CRT 0x0F000010
-#define PTRN_ARM_INSN_CRT 0x0E000010
-
-#define ARM_INSN_MATCH(name, insn) \
- ((insn & MASK_ARM_INSN_##name) == PTRN_ARM_INSN_##name)
-#define THUMB_INSN_MATCH(name, insn) \
- (((insn & 0x0000FFFF) & MASK_THUMB_INSN_##name) == \
- PTRN_THUMB_INSN_##name)
-#define THUMB2_INSN_MATCH(name, insn) \
- ((insn & MASK_THUMB2_INSN_##name) == PTRN_THUMB2_INSN_##name)
-
-#define ARM_INSN_REG_RN(insn) \
- ((insn & 0x000F0000)>>16)
-
-#define ARM_INSN_REG_SET_RN(insn, nreg) \
- { insn &= ~0x000F0000; insn |= nreg<<16; }
-
-#define ARM_INSN_REG_RD(insn) \
- ((insn & 0x0000F000)>>12)
-
-#define ARM_INSN_REG_SET_RD(insn, nreg) \
- { insn &= ~0x0000F000; insn |= nreg<<12; }
-
-#define ARM_INSN_REG_RS(insn) \
- ((insn & 0x00000F00)>>8)
-
-#define ARM_INSN_REG_SET_RS(insn, nreg) \
- { insn &= ~0x00000F00; insn |= nreg<<8; }
-
-#define ARM_INSN_REG_RM(insn) \
- (insn & 0x0000000F)
-
-#define ARM_INSN_REG_SET_RM(insn, nreg) \
- { insn &= ~0x0000000F; insn |= nreg; }
-
-#define ARM_INSN_REG_MR(insn, nreg) \
- (insn & (1 << nreg))
-
-#define ARM_INSN_REG_SET_MR(insn, nreg) \
- { insn |= (1 << nreg); }
-
-#define ARM_INSN_REG_CLEAR_MR(insn, nreg) \
- { insn &= ~(1 << nreg); }
-
-#define THUMB2_INSN_REG_RT(insn) ((insn & 0xf0000000) >> 28)
-#define THUMB2_INSN_REG_RT2(insn) ((insn & 0x0f000000) >> 24)
-#define THUMB2_INSN_REG_RN(insn) (insn & 0x0000000f)
-#define THUMB2_INSN_REG_RD(insn) ((insn & 0x0f000000) >> 24)
-#define THUMB2_INSN_REG_RM(insn) ((insn & 0x000f0000) >> 16)
-
-
-
-
-/**
- * @struct kprobe_ctlblk
- * @brief Per-cpu kprobe control block.
- * @var kprobe_ctlblk::kprobe_status
- * Kprobe status.
- * @var kprobe_ctlblk::prev_kprobe
- * Previous kprobe.
- */
-struct kprobe_ctlblk {
- unsigned long kprobe_status;
- struct prev_kprobe prev_kprobe;
-};
-
-/**
- * @struct arch_specific_insn
- * @brief Architecture specific copy of original instruction.
- * @var arch_specific_insn::insn
- * Copy of the original instruction.
- */
-struct arch_specific_insn {
- kprobe_opcode_t *insn;
-};
-
-typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long,
- unsigned long, unsigned long,
- unsigned long, unsigned long);
-
-struct undef_hook;
-
-void swap_register_undef_hook(struct undef_hook *hook);
-void swap_unregister_undef_hook(struct undef_hook *hook);
-
-int arch_init_module_deps(void);
-
-int arch_make_trampoline_arm(unsigned long addr, unsigned long insn,
- unsigned long *tramp);
-
-struct slot_manager;
-struct kretprobe;
-struct kretprobe_instance;
-int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm);
-void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-
-void swap_arch_arm_kprobe(struct kprobe *p);
-void swap_arch_disarm_kprobe(struct kprobe *p);
-
-int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs);
-int swap_longjmp_break_handler(struct kprobe *p, struct pt_regs *regs);
-
-void save_previous_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *cur_p);
-void restore_previous_kprobe(struct kprobe_ctlblk *kcb);
-void set_current_kprobe(struct kprobe *p,
- struct pt_regs *regs,
- struct kprobe_ctlblk *kcb);
-
-void __naked swap_kretprobe_trampoline(void);
-
-/**
- * @brief Gets arguments of kernel functions.
- *
- * @param regs Pointer to CPU registers data.
- * @param n Number of the argument.
- * @return Argument value.
- */
-static inline unsigned long swap_get_karg(struct pt_regs *regs, unsigned long n)
-{
- switch (n) {
- case 0:
- return regs->ARM_r0;
- case 1:
- return regs->ARM_r1;
- case 2:
- return regs->ARM_r2;
- case 3:
- return regs->ARM_r3;
- }
-
- return *((unsigned long *)regs->ARM_sp + n - 4);
-}
-
-/**
- * @brief swap_get_karg wrapper.
- *
- * @param regs Pointer to CPU registers data.
- * @param n Number of the argument.
- * @return Argument value.
- */
-static inline unsigned long swap_get_sarg(struct pt_regs *regs, unsigned long n)
-{
- return swap_get_karg(regs, n);
-}
-
-/* jumper */
-typedef unsigned long (*jumper_cb_t)(void *);
-
-int set_kjump_cb(struct pt_regs *regs, jumper_cb_t cb,
- void *data, size_t size);
-
-unsigned long get_jump_addr(void);
-int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
- jumper_cb_t cb, void *data, size_t size);
-
-int swap_arch_init_kprobes(void);
-void swap_arch_exit_kprobes(void);
-
-/* void gen_insn_execbuf (void); */
-/* void pc_dep_insn_execbuf (void); */
-/* void gen_insn_execbuf_holder (void); */
-/* void pc_dep_insn_execbuf_holder (void); */
-
-#endif /* _SWAP_ASM_ARM_KPROBES_H */
+++ /dev/null
-/*
- * Function return probe trampoline:
- * - init_kprobes() establishes a probepoint here
- * - When the probed function returns, this probe
- * causes the handlers to fire
- */
-
- .global gen_insn_execbuf
-gen_insn_execbuf:
- nop
- nop
- nop //original instruction
- nop
- ldr pc, [pc, #4] //ssbreak
- nop //retbreak
- nop
- nop //stored PC-4(next insn addr)
-
-
-
- .global pc_dep_insn_execbuf
-pc_dep_insn_execbuf:
- str r0, [sp, #-4]
- ldr r0, [pc, #12]
- nop // instruction with replaced PC
- ldr r0, [sp, #-4]
- ldr pc, [pc, #4] //ssbreak
- nop // retbreak
- nop // stored PC
- nop // stored PC-4 (next insn addr)
-
- .global b_r_insn_execbuf
-b_r_insn_execbuf:
- nop // bx, blx (Rm)
- ldr pc, np1
- nop
- nop
- nop
- nop // retbreak
- nop
-np1: nop // stored PC-4 (next insn addr)
-
- .global b_cond_insn_execbuf
-b_cond_insn_execbuf:
- beq condway
- ldr pc, np2
-condway: ldr pc, bd2
- nop
- nop
- nop // retbreak
-bd2: nop // branch displacement
-np2: nop // stored PC-4 (next insn addr)
-
- .global blx_off_insn_execbuf
-blx_off_insn_execbuf:
- ldreq lr, bd3
- blxeq lr
- ldr pc, np3
- nop
- nop
- nop // retbreak
-bd3: nop // branch displacement
-np3: nop // stored PC-4 (next insn addr)
+++ /dev/null
-/**
- * @file kprobe/arch/asm-arm/trampoline_arm.h
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM/MIPS
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
- * Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>:
- * redesign module for separating core and arch parts
- * @author Alexander Shirshikov <a.shirshikov@samsung.com>:
- * initial implementation for Thumb
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Provides intefrace for trampoline_arm.S
- */
-
-#ifndef __ASM_ARM_TRAMPOLINE_ARM_H
-#define __ASM_ARM_TRAMPOLINE_ARM_H
-
-void gen_insn_execbuf(void);
-void pc_dep_insn_execbuf(void);
-void b_r_insn_execbuf(void);
-void b_cond_insn_execbuf(void);
-void blx_off_insn_execbuf(void);
-
-#endif /* __ASM_ARM_TRAMPOLINE_ARM_H */
+++ /dev/null
-/**
- * arch/asm-x86/swap_kprobes.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- * @author Stanislav Andreev <s.andreev@samsung.com>: added time debug profiling support; BUG() message fix
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) IBM Corporation, 2002, 2004
- *
- * @section DESCRIPTION
- *
- * SWAP krpobes arch-dependend part for x86.
- */
-
-#include<linux/module.h>
-#include <linux/kdebug.h>
-
-#include "swap_kprobes.h"
-#include <kprobe/swap_kprobes.h>
-
-#include <kprobe/swap_kdebug.h>
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_kprobes_deps.h>
-#define SUPRESS_BUG_MESSAGES /**< Debug-off definition. */
-
-
-static int (*swap_fixup_exception)(struct pt_regs *regs);
-static void *(*swap_text_poke)(void *addr, const void *opcode, size_t len);
-static void (*swap_show_registers)(struct pt_regs *regs);
-
-
-/** Stack address. */
-#define stack_addr(regs) ((unsigned long *)kernel_stack_pointer(regs))
-
-
-#define SWAP_SAVE_REGS_STRING \
- /* Skip cs, ip, orig_ax and gs. */ \
- "subl $16, %esp\n" \
- "pushl %fs\n" \
- "pushl %es\n" \
- "pushl %ds\n" \
- "pushl %eax\n" \
- "pushl %ebp\n" \
- "pushl %edi\n" \
- "pushl %esi\n" \
- "pushl %edx\n" \
- "pushl %ecx\n" \
- "pushl %ebx\n"
-#define SWAP_RESTORE_REGS_STRING \
- "popl %ebx\n" \
- "popl %ecx\n" \
- "popl %edx\n" \
- "popl %esi\n" \
- "popl %edi\n" \
- "popl %ebp\n" \
- "popl %eax\n" \
- /* Skip ds, es, fs, gs, orig_ax, and ip. Note: don't pop cs here*/\
- "addl $24, %esp\n"
-
-
-/*
- * Function return probe trampoline:
- * - init_kprobes() establishes a probepoint here
- * - When the probed function returns, this probe
- * causes the handlers to fire
- */
-__asm(
- ".global swap_kretprobe_trampoline\n"
- "swap_kretprobe_trampoline:\n"
- "pushf\n"
- SWAP_SAVE_REGS_STRING
- "movl %esp, %eax\n"
- "call trampoline_probe_handler_x86\n"
- /* move eflags to cs */
- "movl 56(%esp), %edx\n"
- "movl %edx, 52(%esp)\n"
- /* replace saved flags with true return address. */
- "movl %eax, 56(%esp)\n"
- SWAP_RESTORE_REGS_STRING
- "popf\n"
- "ret\n"
-);
-
-/* insert a jmp code */
-static __always_inline void set_jmp_op(void *from, void *to)
-{
- struct __arch_jmp_op {
- char op;
- long raddr;
- } __packed * jop;
- jop = (struct __arch_jmp_op *) from;
- jop->raddr = (long) (to) - ((long) (from) + 5);
- jop->op = RELATIVEJUMP_INSTRUCTION;
-}
-
-/**
- * @brief Check if opcode can be boosted.
- *
- * @param opcodes Opcode to check.
- * @return Non-zero if opcode can be boosted.
- */
-int swap_can_boost(kprobe_opcode_t *opcodes)
-{
-#define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf) \
- (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \
- (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) | \
- (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) | \
- (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf)) \
- << (row % 32))
- /*
- * Undefined/reserved opcodes, conditional jump, Opcode Extension
- * Groups, and some special opcodes can not be boost.
- */
- static const unsigned long twobyte_is_boostable[256 / 32] = {
- /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
- W(0x00, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0) |
- W(0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
- W(0x30, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) |
- W(0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1) |
- W(0x70, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1),
- W(0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
- W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
- W(0xa0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1) |
- W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1),
- W(0xc0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) |
- W(0xd0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1),
- W(0xe0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1) |
- W(0xf0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0)
- /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
-
- };
-#undef W
- kprobe_opcode_t opcode;
- kprobe_opcode_t *orig_opcodes = opcodes;
-retry:
- if (opcodes - orig_opcodes > MAX_INSN_SIZE - 1)
- return 0;
- opcode = *(opcodes++);
-
- /* 2nd-byte opcode */
- if (opcode == 0x0f) {
- if (opcodes - orig_opcodes > MAX_INSN_SIZE - 1)
- return 0;
- return test_bit(*opcodes, twobyte_is_boostable);
- }
-
- switch (opcode & 0xf0) {
- case 0x60:
- if (0x63 < opcode && opcode < 0x67)
- goto retry; /* prefixes */
- /* can't boost Address-size override and bound */
- return (opcode != 0x62 && opcode != 0x67);
- case 0x70:
- return 0; /* can't boost conditional jump */
- case 0xc0:
- /* can't boost software-interruptions */
- return (0xc1 < opcode && opcode < 0xcc) || opcode == 0xcf;
- case 0xd0:
- /* can boost AA* and XLAT */
- return (opcode == 0xd4 || opcode == 0xd5 || opcode == 0xd7);
- case 0xe0:
- /* can boost in/out and absolute jmps */
- return ((opcode & 0x04) || opcode == 0xea);
- case 0xf0:
- if ((opcode & 0x0c) == 0 && opcode != 0xf1)
- goto retry; /* lock/rep(ne) prefix */
- /* clear and set flags can be boost */
- return (opcode == 0xf5 || (0xf7 < opcode && opcode < 0xfe));
- default:
- if (opcode == 0x26 || opcode == 0x36 || opcode == 0x3e)
- goto retry; /* prefixes */
- /* can't boost CS override and call */
- return (opcode != 0x2e && opcode != 0x9a);
- }
-}
-EXPORT_SYMBOL_GPL(swap_can_boost);
-
-/*
- * returns non-zero if opcode modifies the interrupt flag.
- */
-static int is_IF_modifier(kprobe_opcode_t opcode)
-{
- switch (opcode) {
- case 0xfa: /* cli */
- case 0xfb: /* sti */
- case 0xcf: /* iret/iretd */
- case 0x9d: /* popf/popfd */
- return 1;
- }
- return 0;
-}
-
-/**
- * @brief Creates trampoline for kprobe.
- *
- * @param p Pointer to kprobe.
- * @param sm Pointer to slot manager
- * @return 0 on success, error code on error.
- */
-int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm)
-{
- /* insn: must be on special executable page on i386. */
- p->ainsn.insn = swap_slot_alloc(sm);
- if (p->ainsn.insn == NULL)
- return -ENOMEM;
-
- memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
-
- p->opcode = *p->addr;
- p->ainsn.boostable = swap_can_boost(p->addr) ? 0 : -1;
-
- return 0;
-}
-
-/**
- * @brief Prepares singlestep for current CPU.
- *
- * @param p Pointer to kprobe.
- * @param regs Pointer to CPU registers data.
- * @return Void.
- */
-void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
-{
- int cpu = smp_processor_id();
-
- if (p->ss_addr[cpu]) {
- regs->EREG(ip) = (unsigned long)p->ss_addr[cpu];
- p->ss_addr[cpu] = NULL;
- } else {
- regs->EREG(flags) |= TF_MASK;
- regs->EREG(flags) &= ~IF_MASK;
- /* single step inline if the instruction is an int3 */
- if (p->opcode == BREAKPOINT_INSTRUCTION) {
- regs->EREG(ip) = (unsigned long) p->addr;
- /* printk(KERN_INFO "break_insn!!!\n"); */
- } else
- regs->EREG(ip) = (unsigned long) p->ainsn.insn;
- }
-}
-EXPORT_SYMBOL_GPL(prepare_singlestep);
-
-/**
- * @brief Saves previous kprobe.
- *
- * @param kcb Pointer to kprobe_ctlblk struct whereto save current kprobe.
- * @param p_run Pointer to kprobe.
- * @return Void.
- */
-void save_previous_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *cur_p)
-{
- if (kcb->prev_kprobe.kp != NULL) {
- panic("no space to save new probe[]: "
- "task = %d/%s, prev %p, current %p, new %p,",
- current->pid, current->comm, kcb->prev_kprobe.kp->addr,
- swap_kprobe_running()->addr, cur_p->addr);
- }
-
-
- kcb->prev_kprobe.kp = swap_kprobe_running();
- kcb->prev_kprobe.status = kcb->kprobe_status;
-
-}
-
-/**
- * @brief Restores previous kprobe.
- *
- * @param kcb Pointer to kprobe_ctlblk which contains previous kprobe.
- * @return Void.
- */
-void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
-{
- __get_cpu_var(swap_current_kprobe) = kcb->prev_kprobe.kp;
- kcb->kprobe_status = kcb->prev_kprobe.status;
- kcb->prev_kprobe.kp = NULL;
- kcb->prev_kprobe.status = 0;
-}
-
-/**
- * @brief Sets currently running kprobe.
- *
- * @param p Pointer to currently running kprobe.
- * @param regs Pointer to CPU registers data.
- * @param kcb Pointer to kprobe_ctlblk.
- * @return Void.
- */
-void set_current_kprobe(struct kprobe *p,
- struct pt_regs *regs,
- struct kprobe_ctlblk *kcb)
-{
- __get_cpu_var(swap_current_kprobe) = p;
- DBPRINTF("set_current_kprobe[]: p=%p addr=%p\n", p, p->addr);
- kcb->kprobe_saved_eflags = kcb->kprobe_old_eflags =
- (regs->EREG(flags) & (TF_MASK | IF_MASK));
- if (is_IF_modifier(p->opcode))
- kcb->kprobe_saved_eflags &= ~IF_MASK;
-}
-
-static int setup_singlestep(struct kprobe *p, struct pt_regs *regs,
- struct kprobe_ctlblk *kcb)
-{
-#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
- if (p->ainsn.boostable == 1 && !p->post_handler) {
- /* Boost up -- we can execute copied instructions directly */
- swap_reset_current_kprobe();
- regs->ip = (unsigned long)p->ainsn.insn;
- swap_preempt_enable_no_resched();
-
- return 1;
- }
-#endif /* !CONFIG_PREEMPT */
-
- prepare_singlestep(p, regs);
- kcb->kprobe_status = KPROBE_HIT_SS;
-
- return 1;
-}
-
-static int __kprobe_handler(struct pt_regs *regs)
-{
- struct kprobe *p = 0;
- int ret = 0, reenter = 0;
- kprobe_opcode_t *addr = NULL;
- struct kprobe_ctlblk *kcb;
-
- addr = (kprobe_opcode_t *) (regs->EREG(ip) - sizeof(kprobe_opcode_t));
-
- preempt_disable();
-
- kcb = swap_get_kprobe_ctlblk();
- p = swap_get_kprobe(addr);
-
- /* Check we're not actually recursing */
- if (swap_kprobe_running()) {
- if (p) {
- if (kcb->kprobe_status == KPROBE_HIT_SS &&
- *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
- regs->EREG(flags) &= ~TF_MASK;
- regs->EREG(flags) |= kcb->kprobe_saved_eflags;
- goto no_kprobe;
- }
-
-
- /* We have reentered the kprobe_handler(), since
- * another probe was hit while within the handler.
- * We here save the original kprobes variables and
- * just single step on the instruction of the new probe
- * without calling any user handlers.
- */
- save_previous_kprobe(kcb, p);
- set_current_kprobe(p, regs, kcb);
- swap_kprobes_inc_nmissed_count(p);
- prepare_singlestep(p, regs);
- kcb->kprobe_status = KPROBE_REENTER;
-
- return 1;
- } else {
- if (*addr != BREAKPOINT_INSTRUCTION) {
- /* The breakpoint instruction was removed by
- * another cpu right after we hit, no further
- * handling of this interrupt is appropriate
- */
- regs->EREG(ip) -= sizeof(kprobe_opcode_t);
- ret = 1;
- goto no_kprobe;
- }
-
- p = __get_cpu_var(swap_current_kprobe);
- if (p->break_handler && p->break_handler(p, regs))
- goto ss_probe;
-
- goto no_kprobe;
- }
- }
-
- if (!p) {
- if (*addr != BREAKPOINT_INSTRUCTION) {
- /*
- * The breakpoint instruction was removed right
- * after we hit it. Another cpu has removed
- * either a probepoint or a debugger breakpoint
- * at this address. In either case, no further
- * handling of this interrupt is appropriate.
- * Back up over the (now missing) int3 and run
- * the original instruction.
- */
- regs->EREG(ip) -= sizeof(kprobe_opcode_t);
- ret = 1;
- }
-
- if (!p) {
- /* Not one of ours: let kernel handle it */
- DBPRINTF("no_kprobe");
- goto no_kprobe;
- }
- }
-
- set_current_kprobe(p, regs, kcb);
-
- if (!reenter)
- kcb->kprobe_status = KPROBE_HIT_ACTIVE;
-
- if (p->pre_handler) {
- ret = p->pre_handler(p, regs);
- if (ret)
- return ret;
- }
-
-ss_probe:
- setup_singlestep(p, regs, kcb);
-
- return 1;
-
-no_kprobe:
- swap_preempt_enable_no_resched();
-
- return ret;
-}
-
-static int kprobe_handler(struct pt_regs *regs)
-{
- int ret;
-#ifdef SUPRESS_BUG_MESSAGES
- int swap_oops_in_progress;
- /*
- * oops_in_progress used to avoid BUG() messages
- * that slow down kprobe_handler() execution
- */
- swap_oops_in_progress = oops_in_progress;
- oops_in_progress = 1;
-#endif
-
- ret = __kprobe_handler(regs);
-
-#ifdef SUPRESS_BUG_MESSAGES
- oops_in_progress = swap_oops_in_progress;
-#endif
-
- return ret;
-}
-
-/**
- * @brief Probe pre handler.
- *
- * @param p Pointer to fired kprobe.
- * @param regs Pointer to CPU registers data.
- * @return 0.
- */
-int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct jprobe *jp = container_of(p, struct jprobe, kp);
- kprobe_pre_entry_handler_t pre_entry;
- entry_point_t entry;
-
- unsigned long addr;
- struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
-
- pre_entry = (kprobe_pre_entry_handler_t) jp->pre_entry;
- entry = (entry_point_t) jp->entry;
-
- kcb->jprobe_saved_regs = *regs;
- kcb->jprobe_saved_esp = stack_addr(regs);
- addr = (unsigned long)(kcb->jprobe_saved_esp);
-
- /* TBD: As Linus pointed out, gcc assumes that the callee
- * owns the argument space and could overwrite it, e.g.
- * tailcall optimization. So, to be absolutely safe
- * we also save and restore enough stack bytes to cover
- * the argument area. */
- memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
- MIN_STACK_SIZE(addr));
- regs->EREG(flags) &= ~IF_MASK;
- trace_hardirqs_off();
- if (pre_entry)
- p->ss_addr[smp_processor_id()] = (kprobe_opcode_t *)
- pre_entry(jp->priv_arg, regs);
-
- regs->EREG(ip) = (unsigned long)(jp->entry);
-
- return 1;
-}
-
-/**
- * @brief Jprobe return end.
- *
- * @return Void.
- */
-void swap_jprobe_return_end(void);
-
-/**
- * @brief Jprobe return code.
- *
- * @return Void.
- */
-void swap_jprobe_return(void)
-{
- struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
-
- asm volatile(" xchgl %%ebx,%%esp\n"
- " int3\n"
- " .globl swap_jprobe_return_end\n"
- " swap_jprobe_return_end:\n"
- " nop\n"
- : : "b" (kcb->jprobe_saved_esp) : "memory");
-}
-EXPORT_SYMBOL_GPL(swap_jprobe_return);
-
-void arch_ujprobe_return(void)
-{
-}
-
-/*
- * Called after single-stepping. p->addr is the address of the
- * instruction whose first byte has been replaced by the "int 3"
- * instruction. To avoid the SMP problems that can occur when we
- * temporarily put back the original opcode to single-step, we
- * single-stepped a copy of the instruction. The address of this
- * copy is p->ainsn.insn.
- *
- * This function prepares to return from the post-single-step
- * interrupt. We have to fix up the stack as follows:
- *
- * 0) Except in the case of absolute or indirect jump or call instructions,
- * the new eip is relative to the copied instruction. We need to make
- * it relative to the original instruction.
- *
- * 1) If the single-stepped instruction was pushfl, then the TF and IF
- * flags are set in the just-pushed eflags, and may need to be cleared.
- *
- * 2) If the single-stepped instruction was a call, the return address
- * that is atop the stack is the address following the copied instruction.
- * We need to make it the address following the original instruction.
- *
- * This function also checks instruction size for preparing direct execution.
- */
-static void resume_execution(struct kprobe *p,
- struct pt_regs *regs,
- struct kprobe_ctlblk *kcb)
-{
- unsigned long *tos;
- unsigned long copy_eip = (unsigned long) p->ainsn.insn;
- unsigned long orig_eip = (unsigned long) p->addr;
- kprobe_opcode_t insns[2];
-
- regs->EREG(flags) &= ~TF_MASK;
-
- tos = stack_addr(regs);
- insns[0] = p->ainsn.insn[0];
- insns[1] = p->ainsn.insn[1];
-
- switch (insns[0]) {
- case 0x9c: /* pushfl */
- *tos &= ~(TF_MASK | IF_MASK);
- *tos |= kcb->kprobe_old_eflags;
- break;
- case 0xc2: /* iret/ret/lret */
- case 0xc3:
- case 0xca:
- case 0xcb:
- case 0xcf:
- case 0xea: /* jmp absolute -- eip is correct */
- /* eip is already adjusted, no more changes required */
- p->ainsn.boostable = 1;
- goto no_change;
- case 0xe8: /* call relative - Fix return addr */
- *tos = orig_eip + (*tos - copy_eip);
- break;
- case 0x9a: /* call absolute -- same as call absolute, indirect */
- *tos = orig_eip + (*tos - copy_eip);
- goto no_change;
- case 0xff:
- if ((insns[1] & 0x30) == 0x10) {
- /*
- * call absolute, indirect
- * Fix return addr; eip is correct.
- * But this is not boostable
- */
- *tos = orig_eip + (*tos - copy_eip);
- goto no_change;
- } else if (((insns[1] & 0x31) == 0x20) || /* jmp near, absolute
- * indirect */
- ((insns[1] & 0x31) == 0x21)) {
- /* jmp far, absolute indirect */
- /* eip is correct. And this is boostable */
- p->ainsn.boostable = 1;
- goto no_change;
- }
- default:
- break;
- }
-
- if (p->ainsn.boostable == 0) {
- if ((regs->EREG(ip) > copy_eip) &&
- (regs->EREG(ip) - copy_eip) + 5 < MAX_INSN_SIZE) {
- /*
- * These instructions can be executed directly if it
- * jumps back to correct address.
- */
- set_jmp_op((void *)regs->EREG(ip),
- (void *)orig_eip +
- (regs->EREG(ip) - copy_eip));
- p->ainsn.boostable = 1;
- } else {
- p->ainsn.boostable = -1;
- }
- }
-
- regs->EREG(ip) = orig_eip + (regs->EREG(ip) - copy_eip);
-
-no_change:
- return;
-}
-
-/*
- * Interrupts are disabled on entry as trap1 is an interrupt gate and they
- * remain disabled thoroughout this function.
- */
-static int post_kprobe_handler(struct pt_regs *regs)
-{
- struct kprobe *cur = swap_kprobe_running();
- struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
-
- if (!cur)
- return 0;
- if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
- kcb->kprobe_status = KPROBE_HIT_SSDONE;
- cur->post_handler(cur, regs, 0);
- }
-
- resume_execution(cur, regs, kcb);
- regs->EREG(flags) |= kcb->kprobe_saved_eflags;
-#ifndef CONFIG_X86
- trace_hardirqs_fixup_flags(regs->EREG(flags));
-#endif /* CONFIG_X86 */
- /* Restore back the original saved kprobes variables and continue. */
- if (kcb->kprobe_status == KPROBE_REENTER) {
- restore_previous_kprobe(kcb);
- goto out;
- }
- swap_reset_current_kprobe();
-out:
- swap_preempt_enable_no_resched();
-
- /*
- * if somebody else is singlestepping across a probe point, eflags
- * will have TF set, in which case, continue the remaining processing
- * of do_debug, as if this is not a probe hit.
- */
- if (regs->EREG(flags) & TF_MASK)
- return 0;
-
- return 1;
-}
-
-static int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
-{
- struct kprobe *cur = swap_kprobe_running();
- struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
-
- switch (kcb->kprobe_status) {
- case KPROBE_HIT_SS:
- case KPROBE_REENTER:
- /*
- * We are here because the instruction being single
- * stepped caused a page fault. We reset the current
- * kprobe and the eip points back to the probe address
- * and allow the page fault handler to continue as a
- * normal page fault.
- */
- regs->EREG(ip) = (unsigned long) cur->addr;
- regs->EREG(flags) |= kcb->kprobe_old_eflags;
- if (kcb->kprobe_status == KPROBE_REENTER)
- restore_previous_kprobe(kcb);
- else
- swap_reset_current_kprobe();
- swap_preempt_enable_no_resched();
- break;
- case KPROBE_HIT_ACTIVE:
- case KPROBE_HIT_SSDONE:
- /*
- * We increment the nmissed count for accounting,
- * we can also use npre/npostfault count for accouting
- * these specific fault cases.
- */
- swap_kprobes_inc_nmissed_count(cur);
-
- /*
- * We come here because instructions in the pre/post
- * handler caused the page_fault, this could happen
- * if handler tries to access user space by
- * copy_from_user(), get_user() etc. Let the
- * user-specified handler try to fix it first.
- */
- if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
- return 1;
-
- /*
- * In case the user-specified fault handler returned
- * zero, try to fix up.
- */
- if (swap_fixup_exception(regs))
- return 1;
-
- /*
- * fixup_exception() could not handle it,
- * Let do_page_fault() fix it.
- */
- break;
- default:
- break;
- }
- return 0;
-}
-
-static int kprobe_exceptions_notify(struct notifier_block *self,
- unsigned long val, void *data)
-{
- struct die_args *args = (struct die_args *) data;
- int ret = NOTIFY_DONE;
-
- DBPRINTF("val = %ld, data = 0x%X", val, (unsigned int) data);
-
- if (args->regs == NULL || user_mode_vm(args->regs))
- return ret;
-
- DBPRINTF("switch (val) %lu %d %d", val, DIE_INT3, DIE_TRAP);
- switch (val) {
-#ifdef CONFIG_KPROBES
- case DIE_INT3:
-#else
- case DIE_TRAP:
-#endif
- DBPRINTF("before kprobe_handler ret=%d %p",
- ret, args->regs);
- if (kprobe_handler (args->regs))
- ret = NOTIFY_STOP;
- DBPRINTF("after kprobe_handler ret=%d %p",
- ret, args->regs);
- break;
- case DIE_DEBUG:
- if (post_kprobe_handler(args->regs))
- ret = NOTIFY_STOP;
- break;
- case DIE_GPF:
- /* swap_kprobe_running() needs smp_processor_id() */
- preempt_disable();
- if (swap_kprobe_running() &&
- kprobe_fault_handler(args->regs, args->trapnr))
- ret = NOTIFY_STOP;
- preempt_enable();
- break;
- default:
- break;
- }
- DBPRINTF("ret=%d", ret);
- /* if(ret == NOTIFY_STOP) */
- /* handled_exceptions++; */
-
- return ret;
-}
-
-static struct notifier_block kprobe_exceptions_nb = {
- .notifier_call = kprobe_exceptions_notify,
- .priority = INT_MAX
-};
-
-/**
- * @brief Longjump break handler.
- *
- * @param p Pointer to fired kprobe.
- * @param regs Pointer to CPU registers data.
- * @return 0 on success.
- */
-int swap_longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
- u8 *addr = (u8 *) (regs->EREG(ip) - 1);
- unsigned long stack_addr = (unsigned long) (kcb->jprobe_saved_esp);
- struct jprobe *jp = container_of(p, struct jprobe, kp);
-
- DBPRINTF("p = %p\n", p);
-
- if ((addr > (u8 *)swap_jprobe_return) &&
- (addr < (u8 *)swap_jprobe_return_end)) {
- if (stack_addr(regs) != kcb->jprobe_saved_esp) {
- struct pt_regs *saved_regs = &kcb->jprobe_saved_regs;
- printk(KERN_INFO "current esp %p does not match saved esp %p\n",
- stack_addr(regs), kcb->jprobe_saved_esp);
- printk(KERN_INFO "Saved registers for jprobe %p\n", jp);
- swap_show_registers(saved_regs);
- printk(KERN_INFO "Current registers\n");
- swap_show_registers(regs);
- panic("BUG");
- /* BUG(); */
- }
- *regs = kcb->jprobe_saved_regs;
- memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack,
- MIN_STACK_SIZE(stack_addr));
- swap_preempt_enable_no_resched();
- return 1;
- }
-
- return 0;
-}
-
-/**
- * @brief Arms kprobe.
- *
- * @param p Pointer to target kprobe.
- * @return Void.
- */
-void swap_arch_arm_kprobe(struct kprobe *p)
-{
- swap_text_poke(p->addr,
- ((unsigned char[]){BREAKPOINT_INSTRUCTION}), 1);
-}
-
-/**
- * @brief Disarms kprobe.
- *
- * @param p Pointer to target kprobe.
- * @return Void.
- */
-void swap_arch_disarm_kprobe(struct kprobe *p)
-{
- swap_text_poke(p->addr, &p->opcode, 1);
-}
-
-static __used void *trampoline_probe_handler_x86(struct pt_regs *regs)
-{
- return (void *)trampoline_probe_handler(NULL, regs);
-}
-
-/**
- * @brief Prepares kretprobes, saves ret address, makes function return to
- * trampoline.
- *
- * @param ri Pointer to kretprobe_instance.
- * @param regs Pointer to CPU registers data.
- * @return Void.
- */
-void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- unsigned long *ptr_ret_addr = stack_addr(regs);
-
- /* for __switch_to probe */
- if ((unsigned long)ri->rp->kp.addr == sched_addr) {
- ri->sp = NULL;
- ri->task = (struct task_struct *)regs->dx;
- } else {
- ri->sp = ptr_ret_addr;
- }
-
- /* Save the return address */
- ri->ret_addr = (unsigned long *)*ptr_ret_addr;
-
- /* Replace the return addr with trampoline addr */
- *ptr_ret_addr = (unsigned long)&swap_kretprobe_trampoline;
-}
-
-
-
-
-
-/*
- ******************************************************************************
- * kjumper *
- ******************************************************************************
- */
-struct kj_cb_data {
- struct pt_regs regs;
- struct kprobe *p;
-
- jumper_cb_t cb;
- char data[0];
-};
-
-static struct kj_cb_data * __used kjump_handler(struct kj_cb_data *data)
-{
- /* call callback */
- data->cb(data->data);
-
- return data;
-}
-
-void kjump_trampoline(void);
-void kjump_trampoline_int3(void);
-__asm(
- "kjump_trampoline:\n"
- "call kjump_handler\n"
- "kjump_trampoline_int3:\n"
- "nop\n" /* for restore_regs_kp */
-);
-
-int set_kjump_cb(struct pt_regs *regs, jumper_cb_t cb, void *data, size_t size)
-{
- struct kj_cb_data *cb_data;
-
- cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
- if (cb_data == NULL)
- return -ENOMEM;
-
- /* save regs */
- cb_data->regs = *regs;
-
- cb_data->p = swap_kprobe_running();
- cb_data->cb = cb;
-
- /* save data */
- if (size)
- memcpy(cb_data->data, data, size);
-
- /* save pointer cb_data at ax */
- regs->ax = (long)cb_data;
-
- /* jump to kjump_trampoline */
- regs->ip = (unsigned long)&kjump_trampoline;
-
- swap_reset_current_kprobe();
- swap_preempt_enable_no_resched();
-
- return 1;
-}
-EXPORT_SYMBOL_GPL(set_kjump_cb);
-
-static int restore_regs_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct kj_cb_data *data = (struct kj_cb_data *)regs->ax;
- struct kprobe *kp = data->p;
- struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
-
- /* restore regs */
- *regs = data->regs;
-
- /* FIXME: potential memory leak, when process kill */
- kfree(data);
-
- kcb = swap_get_kprobe_ctlblk();
-
- set_current_kprobe(kp, regs, kcb);
- setup_singlestep(kp, regs, kcb);
-
- return 1;
-}
-
-static struct kprobe restore_regs_kp = {
- .pre_handler = restore_regs_pre_handler,
- .addr = (kprobe_opcode_t *)&kjump_trampoline_int3, /* nop */
-};
-
-static int kjump_init(void)
-{
- int ret;
-
- ret = swap_register_kprobe(&restore_regs_kp);
- if (ret)
- printk(KERN_INFO "ERROR: kjump_init(), ret=%d\n", ret);
-
- return ret;
-}
-
-static void kjump_exit(void)
-{
- swap_unregister_kprobe(&restore_regs_kp);
-}
-
-
-
-
-
-/*
- ******************************************************************************
- * jumper *
- ******************************************************************************
- */
-struct cb_data {
- unsigned long ret_addr;
- unsigned long bx;
-
- jumper_cb_t cb;
- char data[0];
-};
-
-static unsigned long __used get_bx(struct cb_data *data)
-{
- return data->bx;
-}
-
-static unsigned long __used jump_handler(struct cb_data *data)
-{
- unsigned long ret_addr = data->ret_addr;
-
- /* call callback */
- data->cb(data->data);
-
- /* FIXME: potential memory leak, when process kill */
- kfree(data);
-
- return ret_addr;
-}
-
-void jump_trampoline(void);
-__asm(
- "jump_trampoline:\n"
- "pushf\n"
- SWAP_SAVE_REGS_STRING
- "movl %ebx, %eax\n" /* data --> ax */
- "call get_bx\n"
- "movl %eax, (%esp)\n" /* restore bx */
- "movl %ebx, %eax\n" /* data --> ax */
- "call jump_handler\n"
- /* move flags to cs */
- "movl 56(%esp), %edx\n"
- "movl %edx, 52(%esp)\n"
- /* replace saved flags with true return address. */
- "movl %eax, 56(%esp)\n"
- SWAP_RESTORE_REGS_STRING
- "popf\n"
- "ret\n"
-);
-
-unsigned long get_jump_addr(void)
-{
- return (unsigned long)&jump_trampoline;
-}
-EXPORT_SYMBOL_GPL(get_jump_addr);
-
-int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
- jumper_cb_t cb, void *data, size_t size)
-{
- struct cb_data *cb_data;
-
- cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
- if (cb_data == NULL)
- return -ENOMEM;
-
- /* save data */
- if (size)
- memcpy(cb_data->data, data, size);
-
- /* save info for restore */
- cb_data->ret_addr = ret_addr;
- cb_data->cb = cb;
- cb_data->bx = regs->bx;
-
- /* save cb_data to bx */
- regs->bx = (long)cb_data;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(set_jump_cb);
-
-
-
-
-
-/**
- * @brief Initializes x86 module deps.
- *
- * @return 0 on success, negative error code on error.
- */
-int arch_init_module_deps()
-{
- const char *sym;
-
- sym = "fixup_exception";
- swap_fixup_exception = (void *)swap_ksyms(sym);
- if (swap_fixup_exception == NULL)
- goto not_found;
-
- sym = "text_poke";
- swap_text_poke = (void *)swap_ksyms(sym);
- if (swap_text_poke == NULL)
- goto not_found;
-
- sym = "show_regs";
- swap_show_registers = (void *)swap_ksyms(sym);
- if (swap_show_registers == NULL)
- goto not_found;
-
- return 0;
-
-not_found:
- printk(KERN_INFO "ERROR: symbol %s(...) not found\n", sym);
- return -ESRCH;
-}
-
-/**
- * @brief Initializes kprobes module for ARM arch.
- *
- * @return 0 on success, error code on error.
- */
-int swap_arch_init_kprobes(void)
-{
- int ret;
-
- ret = register_die_notifier(&kprobe_exceptions_nb);
- if (ret)
- return ret;
-
- ret = kjump_init();
- if (ret)
- unregister_die_notifier(&kprobe_exceptions_nb);
-
- return ret;
-}
-
-/**
- * @brief Uninitializes kprobe module.
- *
- * @return Void.
- */
-void swap_arch_exit_kprobes(void)
-{
- kjump_exit();
- unregister_die_notifier(&kprobe_exceptions_nb);
-}
+++ /dev/null
-/**
- * @file kprobe/arch/asm-x86/swap_kprobes.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) IBM Corporation, 2002, 2004
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Arch-dependent kprobes interface for x86 arch.
- */
-
-#ifndef _SWAP_ASM_X86_KPROBES_H
-#define _SWAP_ASM_X86_KPROBES_H
-
-
-#include <linux/version.h>
-#include <kprobe/swap_kprobes_deps.h>
-
-/**
- * @brief Opcode type.
- */
-typedef u8 kprobe_opcode_t;
-
-#define BREAKPOINT_INSTRUCTION 0xcc
-#define RELATIVEJUMP_INSTRUCTION 0xe9
-
-#define BP_INSN_SIZE 1
-#define MAX_INSN_SIZE 16
-#define MAX_STACK_SIZE 64
-
-#define MIN_STACK_SIZE(ADDR) (((MAX_STACK_SIZE) < \
- (((unsigned long)current_thread_info()) \
- + THREAD_SIZE - (ADDR))) \
- ? (MAX_STACK_SIZE) \
- : (((unsigned long)current_thread_info()) \
- + THREAD_SIZE - (ADDR)))
-
-
-#define EREG(rg) rg
-#define XREG(rg) rg
-#define ORIG_EAX_REG orig_ax
-
-
-#define TF_MASK X86_EFLAGS_TF
-#define IF_MASK X86_EFLAGS_IF
-#define UPROBES_TRAMP_LEN (MAX_INSN_SIZE+sizeof(kprobe_opcode_t))
-#define UPROBES_TRAMP_INSN_IDX 0
-#define UPROBES_TRAMP_RET_BREAK_IDX MAX_INSN_SIZE
-#define KPROBES_TRAMP_LEN MAX_INSN_SIZE
-#define KPROBES_TRAMP_INSN_IDX 0
-
-static inline unsigned long arch_get_task_pc(struct task_struct *p)
-{
- /* FIXME: Not implemented yet */
- return 0;
-}
-
-static inline void arch_set_task_pc(struct task_struct *p, unsigned long val)
-{
- /* FIXME: Not implemented yet */
-}
-
-static inline struct pt_regs *swap_get_syscall_uregs(unsigned long sp)
-{
- return NULL; /* FIXME currently not implemented for x86 */
-}
-
-static inline unsigned long swap_get_stack_ptr(struct pt_regs *regs)
-{
- return regs->EREG(sp);
-}
-
-static inline void swap_set_stack_ptr(struct pt_regs *regs, unsigned long sp)
-{
- regs->EREG(sp) = sp;
-}
-
-static inline unsigned long swap_get_instr_ptr(struct pt_regs *regs)
-{
- return regs->EREG(ip);
-}
-
-static inline void swap_set_instr_ptr(struct pt_regs *regs, unsigned long val)
-{
- regs->EREG(ip) = val;
-}
-
-static inline unsigned long swap_get_ret_addr(struct pt_regs *regs)
-{
- unsigned long addr = 0;
- read_proc_vm_atomic(current, regs->EREG(sp), &addr, sizeof(addr));
- return addr;
-}
-
-static inline void swap_set_ret_addr(struct pt_regs *regs, unsigned long val)
-{
- write_proc_vm_atomic(current, regs->EREG(sp), &val, sizeof(val));
-}
-
-static inline unsigned long swap_get_arg(struct pt_regs *regs, int num)
-{
- unsigned long arg = 0;
- read_proc_vm_atomic(current, regs->EREG(sp) + (1 + num) * 4,
- &arg, sizeof(arg));
- return arg;
-}
-
-static inline void swap_set_arg(struct pt_regs *regs, int num,
- unsigned long val)
-{
- write_proc_vm_atomic(current, regs->EREG(sp) + (1 + num) * 4,
- &val, sizeof(val));
-}
-
-static inline int swap_fp_backtrace(struct task_struct *task,
- unsigned long *buf, int max_cnt)
-{
- int i = 0;
- struct pt_regs *regs;
-
- struct {
- unsigned long next;
- unsigned long raddr;
- } frame;
-
-
- regs = task_pt_regs(task);
- frame.next = regs->EREG(bp);
- frame.raddr = swap_get_ret_addr(regs);
-
- while (frame.next && i < max_cnt) {
- if (read_proc_vm_atomic(task, frame.next, &frame, sizeof(frame))
- == sizeof(frame))
- buf[i++] = frame.raddr;
- else
- break;
- }
-
- return i;
-}
-
-/**
- * @struct prev_kprobe
- * @brief Stores previous kprobe.
- * @var prev_kprobe::kp
- * Pointer to kprobe struct.
- * @var prev_kprobe::status
- * Kprobe status.
- */
-struct prev_kprobe {
- struct kprobe *kp;
- unsigned long status;
-};
-
-/**
- * @struct kprobe_ctlblk
- * @brief Per-cpu kprobe control block.
- * @var kprobe_ctlblk::kprobe_status
- * Kprobe status.
- * @var kprobe_ctlblk::prev_kprobe
- * Previous kprobe.
- */
-struct kprobe_ctlblk {
- unsigned long kprobe_status;
- struct prev_kprobe prev_kprobe;
- struct pt_regs jprobe_saved_regs;
- unsigned long kprobe_old_eflags;
- unsigned long kprobe_saved_eflags;
- unsigned long *jprobe_saved_esp;
- kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
-};
-
-
-/**
- * @struct arch_specific_insn
- * @brief Architecture specific copy of original instruction.
- * @var arch_specific_insn::insn
- * Copy of the original instruction.
- * @var arch_specific_insn::boostable
- * If this flag is not 0, this kprobe can be boost when its
- * post_handler and break_handler is not set.
- */
-struct arch_specific_insn {
- kprobe_opcode_t *insn;
- int boostable;
-};
-
-/**
- * @brief Entry point.
- */
-typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long,
- unsigned long, unsigned long,
- unsigned long, unsigned long);
-
-int arch_init_module_deps(void);
-
-struct slot_manager;
-struct kretprobe_instance;
-
-int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm);
-void swap_arch_arm_kprobe(struct kprobe *p);
-void swap_arch_disarm_kprobe(struct kprobe *p);
-void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
- struct pt_regs *regs);
-void swap_kretprobe_trampoline(void);
-
-void restore_previous_kprobe(struct kprobe_ctlblk *kcb);
-int swap_can_boost(kprobe_opcode_t *opcodes);
-static inline int arch_check_insn(struct arch_specific_insn *ainsn)
-{
- return 0;
-}
-
-static inline unsigned long swap_get_karg(struct pt_regs *regs, unsigned long n)
-{
- switch (n) {
- case 0:
- return regs->ax;
- case 1:
- return regs->dx;
- case 2:
- return regs->cx;
- }
-
- /*
- * 2 = 3 - 1
- * 3 - arguments from registers
- * 1 - return address saved on top of the stack
- */
- return *((unsigned long *)kernel_stack_pointer(regs) + n - 2);
-}
-
-static inline unsigned long swap_get_sarg(struct pt_regs *regs, unsigned long n)
-{
- /* 1 - return address saved on top of the stack */
- return *((unsigned long *)kernel_stack_pointer(regs) + n + 1);
-}
-
-/* jumper */
-typedef unsigned long (*jumper_cb_t)(void *);
-
-int set_kjump_cb(struct pt_regs *regs, jumper_cb_t cb,
- void *data, size_t size);
-
-unsigned long get_jump_addr(void);
-int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
- jumper_cb_t cb, void *data, size_t size);
-
-int swap_arch_init_kprobes(void);
-void swap_arch_exit_kprobes(void);
-
-#endif /* _SWAP_ASM_X86_KPROBES_H */
+++ /dev/null
-/**
- * @file kprobe/swap_kdebug.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Header for debug purposes.
- */
-
-
-#ifndef _SWAP_KPROBE_DEBUG_H
-#define _SWAP_KPROBE_DEBUG_H
-
-/* #define _DEBUG */
-
-#ifdef _DEBUG
-#define DBPRINTF(format, args...) do { \
- if (1) { \
- char *f = __FILE__; \
- char *n = strrchr(f, '/'); \
- printk(KERN_INFO "%s : %u : %s : " format "\n" , \
- (n) ? n+1 : f, __LINE__, __func__, ##args); \
- } \
- } while (0)
-#else
-#define DBPRINTF(format, args...)
-#endif
-
-
-#endif /* _SWAP_KPROBE_DEBUG_H */
+++ /dev/null
-/**
- * kprobe/swap_kprobes.c
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM and MIPS
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) IBM Corporation, 2002, 2004
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * SWAP kprobe implementation. Dynamic kernel functions instrumentation.
- */
-
-#include <linux/version.h>
-
-#include <linux/hash.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/stop_machine.h>
-
-#include <ksyms/ksyms.h>
-#include <master/swap_initializer.h>
-#include <swap-asm/swap_kprobes.h>
-
-#include "swap_slots.h"
-#include "swap_kdebug.h"
-#include "swap_kprobes.h"
-#include "swap_kprobes_deps.h"
-
-/**
- * @var sched_addr
- * @brief Scheduler address.
- */
-unsigned long sched_addr;
-static unsigned long exit_addr;
-static unsigned long do_group_exit_addr;
-static unsigned long sys_exit_group_addr;
-static unsigned long sys_exit_addr;
-
-/**
- * @var sm
- * @brief Current slot manager. Slots are the places where trampolines are
- * located.
- */
-struct slot_manager sm;
-
-DEFINE_PER_CPU(struct kprobe *, swap_current_kprobe);
-static DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
-
-static DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */
-static DEFINE_PER_CPU(struct kprobe *, kprobe_instance);
-
-struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
-static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
-
-/**
- * @var kprobe_count
- * @brief Count of kprobes.
- */
-atomic_t kprobe_count;
-EXPORT_SYMBOL_GPL(kprobe_count);
-
-
-static void *(*module_alloc)(unsigned long size);
-static void *(*module_free)(struct module *mod, void *module_region);
-
-static void *__wrapper_module_alloc(unsigned long size)
-{
- return module_alloc(size);
-}
-
-static void *__wrapper_module_free(void *module_region)
-{
- return module_free(NULL, module_region);
-}
-
-static void *sm_alloc(struct slot_manager *sm)
-{
- return __wrapper_module_alloc(PAGE_SIZE);
-}
-
-static void sm_free(struct slot_manager *sm, void *ptr)
-{
- __wrapper_module_free(ptr);
-}
-
-static void init_sm(void)
-{
- sm.slot_size = KPROBES_TRAMP_LEN;
- sm.alloc = sm_alloc;
- sm.free = sm_free;
- INIT_HLIST_HEAD(&sm.page_list);
-}
-
-static void exit_sm(void)
-{
- /* FIXME: free */
-}
-
-static void kretprobe_assert(struct kretprobe_instance *ri,
- unsigned long orig_ret_address,
- unsigned long trampoline_address)
-{
- if (!orig_ret_address || (orig_ret_address == trampoline_address)) {
- struct task_struct *task;
- if (ri == NULL)
- panic("kretprobe BUG!: ri = NULL\n");
-
- task = ri->task;
-
- if (task == NULL)
- panic("kretprobe BUG!: task = NULL\n");
-
- if (ri->rp == NULL)
- panic("kretprobe BUG!: ri->rp = NULL\n");
-
- panic("kretprobe BUG!: "
- "Processing kretprobe %p @ %p (%d/%d - %s)\n",
- ri->rp, ri->rp->kp.addr, ri->task->tgid,
- ri->task->pid, ri->task->comm);
- }
-}
-
-/* We have preemption disabled.. so it is safe to use __ versions */
-static inline void set_kprobe_instance(struct kprobe *kp)
-{
- __get_cpu_var(kprobe_instance) = kp;
-}
-
-static inline void reset_kprobe_instance(void)
-{
- __get_cpu_var(kprobe_instance) = NULL;
-}
-
-/**
- * @brief Gets the current kprobe on this CPU.
- *
- * @return Pointer to the current kprobe.
- */
-struct kprobe *swap_kprobe_running(void)
-{
- return __get_cpu_var(swap_current_kprobe);
-}
-
-/**
- * @brief Sets the current kprobe to NULL.
- *
- * @return Void.
- */
-void swap_reset_current_kprobe(void)
-{
- __get_cpu_var(swap_current_kprobe) = NULL;
-}
-
-/**
- * @brief Gets kprobe_ctlblk for the current CPU.
- *
- * @return Current CPU struct kprobe_ctlblk.
- */
-struct kprobe_ctlblk *swap_get_kprobe_ctlblk(void)
-{
- return &__get_cpu_var(kprobe_ctlblk);
-}
-
-/*
- * This routine is called either:
- * - under the kprobe_mutex - during kprobe_[un]register()
- * OR
- * - with preemption disabled - from arch/xxx/kernel/kprobes.c
- */
-
-/**
- * @brief Gets kprobe.
- *
- * @param addr Probe address.
- * @return Kprobe for addr.
- */
-struct kprobe *swap_get_kprobe(void *addr)
-{
- struct hlist_head *head;
- struct kprobe *p;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)];
- swap_hlist_for_each_entry_rcu(p, node, head, hlist) {
- if (p->addr == addr)
- return p;
- }
-
- return NULL;
-}
-
-/*
- * Aggregate handlers for multiple kprobes support - these handlers
- * take care of invoking the individual kprobe handlers on p->list
- */
-static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct kprobe *kp;
- int ret;
-
- list_for_each_entry_rcu(kp, &p->list, list) {
- if (kp->pre_handler) {
- set_kprobe_instance(kp);
- ret = kp->pre_handler(kp, regs);
- if (ret)
- return ret;
- }
- reset_kprobe_instance();
- }
-
- return 0;
-}
-
-static void aggr_post_handler(struct kprobe *p,
- struct pt_regs *regs,
- unsigned long flags)
-{
- struct kprobe *kp;
-
- list_for_each_entry_rcu(kp, &p->list, list) {
- if (kp->post_handler) {
- set_kprobe_instance(kp);
- kp->post_handler(kp, regs, flags);
- reset_kprobe_instance();
- }
- }
-}
-
-static int aggr_fault_handler(struct kprobe *p,
- struct pt_regs *regs,
- int trapnr)
-{
- struct kprobe *cur = __get_cpu_var(kprobe_instance);
-
- /*
- * if we faulted "during" the execution of a user specified
- * probe handler, invoke just that probe's fault handler
- */
- if (cur && cur->fault_handler) {
- if (cur->fault_handler(cur, regs, trapnr))
- return 1;
- }
-
- return 0;
-}
-
-static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct kprobe *cur = __get_cpu_var(kprobe_instance);
- int ret = 0;
- DBPRINTF("cur = 0x%p\n", cur);
- if (cur)
- DBPRINTF("cur = 0x%p cur->break_handler = 0x%p\n",
- cur, cur->break_handler);
-
- if (cur && cur->break_handler) {
- if (cur->break_handler(cur, regs))
- ret = 1;
- }
- reset_kprobe_instance();
-
- return ret;
-}
-
-/**
- * @brief Walks the list and increments nmissed count for multiprobe case.
- *
- * @param p Pointer to the missed kprobe.
- * @return Void.
- */
-void swap_kprobes_inc_nmissed_count(struct kprobe *p)
-{
- struct kprobe *kp;
- if (p->pre_handler != aggr_pre_handler) {
- p->nmissed++;
- } else {
- list_for_each_entry_rcu(kp, &p->list, list) {
- ++kp->nmissed;
- }
- }
-}
-
-static int alloc_nodes_kretprobe(struct kretprobe *rp);
-
-/* Called with kretprobe_lock held */
-static struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp)
-{
- struct kretprobe_instance *ri;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
- return ri;
- }
-
- if (!alloc_nodes_kretprobe(rp)) {
- swap_hlist_for_each_entry(ri, node, &rp->free_instances,
- uflist) {
- return ri;
- }
- }
-
- return NULL;
-}
-
-/* Called with kretprobe_lock held */
-static struct kretprobe_instance *
-get_free_rp_inst_no_alloc(struct kretprobe *rp)
-{
- struct kretprobe_instance *ri;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
- return ri;
- }
-
- return NULL;
-}
-
-/* Called with kretprobe_lock held */
-static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp)
-{
- struct kretprobe_instance *ri;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
- return ri;
- }
-
- return NULL;
-}
-
-/* Called with kretprobe_lock held */
-static void add_rp_inst(struct kretprobe_instance *ri)
-{
- /*
- * Remove rp inst off the free list -
- * Add it back when probed function returns
- */
- hlist_del(&ri->uflist);
-
- /* Add rp inst onto table */
- INIT_HLIST_NODE(&ri->hlist);
-
- hlist_add_head(&ri->hlist,
- &kretprobe_inst_table[hash_ptr(ri->task,
- KPROBE_HASH_BITS)]);
-
- /* Also add this rp inst to the used list. */
- INIT_HLIST_NODE(&ri->uflist);
- hlist_add_head(&ri->uflist, &ri->rp->used_instances);
-}
-
-/* Called with kretprobe_lock held */
-static void recycle_rp_inst(struct kretprobe_instance *ri)
-{
- if (ri->rp) {
- hlist_del(&ri->hlist);
- /* remove rp inst off the used list */
- hlist_del(&ri->uflist);
- /* put rp inst back onto the free list */
- INIT_HLIST_NODE(&ri->uflist);
- hlist_add_head(&ri->uflist, &ri->rp->free_instances);
- }
-}
-
-static struct hlist_head *kretprobe_inst_table_head(void *hash_key)
-{
- return &kretprobe_inst_table[hash_ptr(hash_key, KPROBE_HASH_BITS)];
-}
-
-static void free_rp_inst(struct kretprobe *rp)
-{
- struct kretprobe_instance *ri;
- while ((ri = get_free_rp_inst_no_alloc(rp)) != NULL) {
- hlist_del(&ri->uflist);
- kfree(ri);
- }
-}
-
-/*
- * Keep all fields in the kprobe consistent
- */
-static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p)
-{
- memcpy(&p->opcode, &old_p->opcode, sizeof(kprobe_opcode_t));
- memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_specific_insn));
-}
-
-/*
- * Add the new probe to old_p->list. Fail if this is the
- * second jprobe at the address - two jprobes can't coexist
- */
-static int add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
-{
- if (p->break_handler) {
- if (old_p->break_handler)
- return -EEXIST;
-
- list_add_tail_rcu(&p->list, &old_p->list);
- old_p->break_handler = aggr_break_handler;
- } else {
- list_add_rcu(&p->list, &old_p->list);
- }
-
- if (p->post_handler && !old_p->post_handler)
- old_p->post_handler = aggr_post_handler;
-
- return 0;
-}
-
-/**
- * hlist_replace_rcu - replace old entry by new one
- * @old : the element to be replaced
- * @new : the new element to insert
- *
- * The @old entry will be replaced with the @new entry atomically.
- */
-inline void swap_hlist_replace_rcu(struct hlist_node *old,
- struct hlist_node *new)
-{
- struct hlist_node *next = old->next;
-
- new->next = next;
- new->pprev = old->pprev;
- smp_wmb();
- if (next)
- new->next->pprev = &new->next;
- if (new->pprev)
- *new->pprev = new;
- old->pprev = LIST_POISON2;
-}
-
-/*
- * Fill in the required fields of the "manager kprobe". Replace the
- * earlier kprobe in the hlist with the manager kprobe
- */
-static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
-{
- copy_kprobe(p, ap);
- ap->addr = p->addr;
- ap->pre_handler = aggr_pre_handler;
- ap->fault_handler = aggr_fault_handler;
- if (p->post_handler)
- ap->post_handler = aggr_post_handler;
- if (p->break_handler)
- ap->break_handler = aggr_break_handler;
-
- INIT_LIST_HEAD(&ap->list);
- list_add_rcu(&p->list, &ap->list);
-
- swap_hlist_replace_rcu(&p->hlist, &ap->hlist);
-}
-
-/*
- * This is the second or subsequent kprobe at the address - handle
- * the intricacies
- */
-static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p)
-{
- int ret = 0;
- struct kprobe *ap;
- DBPRINTF("start\n");
-
- DBPRINTF("p = %p old_p = %p\n", p, old_p);
- if (old_p->pre_handler == aggr_pre_handler) {
- DBPRINTF("aggr_pre_handler\n");
-
- copy_kprobe(old_p, p);
- ret = add_new_kprobe(old_p, p);
- } else {
- DBPRINTF("kzalloc\n");
-#ifdef kzalloc
- ap = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
-#else
- ap = kmalloc(sizeof(struct kprobe), GFP_KERNEL);
- if (ap)
- memset(ap, 0, sizeof(struct kprobe));
-#endif
- if (!ap)
- return -ENOMEM;
- add_aggr_kprobe(ap, old_p);
- copy_kprobe(ap, p);
- DBPRINTF("ap = %p p = %p old_p = %p\n", ap, p, old_p);
- ret = add_new_kprobe(ap, p);
- }
-
- return ret;
-}
-
-static void remove_kprobe(struct kprobe *p)
-{
- /* TODO: check boostable for x86 and MIPS */
- swap_slot_free(&sm, p->ainsn.insn);
-}
-
-/**
- * @brief Registers kprobe.
- *
- * @param p Pointer to the target kprobe.
- * @return 0 on success, error code on error.
- */
-int swap_register_kprobe(struct kprobe *p)
-{
- struct kprobe *old_p;
- int ret = 0;
- /*
- * If we have a symbol_name argument look it up,
- * and add it to the address. That way the addr
- * field can either be global or relative to a symbol.
- */
- if (p->symbol_name) {
- if (p->addr)
- return -EINVAL;
- p->addr = (kprobe_opcode_t *)swap_ksyms(p->symbol_name);
- }
-
- if (!p->addr)
- return -EINVAL;
- DBPRINTF("p->addr = 0x%p\n", p->addr);
- p->addr = (kprobe_opcode_t *)(((char *)p->addr) + p->offset);
- DBPRINTF("p->addr = 0x%p p = 0x%p\n", p->addr, p);
-
-#ifdef KPROBES_PROFILE
- p->start_tm.tv_sec = p->start_tm.tv_usec = 0;
- p->hnd_tm_sum.tv_sec = p->hnd_tm_sum.tv_usec = 0;
- p->count = 0;
-#endif
- p->mod_refcounted = 0;
- p->nmissed = 0;
- INIT_LIST_HEAD(&p->list);
-
- old_p = swap_get_kprobe(p->addr);
- if (old_p) {
- ret = register_aggr_kprobe(old_p, p);
- if (!ret)
- atomic_inc(&kprobe_count);
- goto out;
- }
- ret = swap_arch_prepare_kprobe(p, &sm);
- if (ret != 0)
- goto out;
-
- DBPRINTF("before out ret = 0x%x\n", ret);
- INIT_HLIST_NODE(&p->hlist);
- hlist_add_head_rcu(&p->hlist,
- &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
- swap_arch_arm_kprobe(p);
-
-out:
- DBPRINTF("out ret = 0x%x\n", ret);
- return ret;
-}
-EXPORT_SYMBOL_GPL(swap_register_kprobe);
-
-static void swap_unregister_valid_kprobe(struct kprobe *p, struct kprobe *old_p)
-{
- struct kprobe *list_p;
-
- if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) &&
- (p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) {
- /* Only probe on the hash list */
- swap_arch_disarm_kprobe(p);
-
- /* FIXME: move sync out from atomic context */
- if (!in_atomic())
- synchronize_sched();
-
- hlist_del_rcu(&old_p->hlist);
- remove_kprobe(old_p);
-
- if (p != old_p) {
- list_del_rcu(&old_p->list);
- kfree(old_p);
- }
- /* Synchronize and remove probe in bottom */
- } else {
- list_del_rcu(&p->list);
-
- if (p->break_handler)
- old_p->break_handler = NULL;
- if (p->post_handler) {
- list_for_each_entry_rcu(list_p, &old_p->list, list)
- if (list_p->post_handler)
- return;
-
- old_p->post_handler = NULL;
- }
- }
- /* Set NULL addr for reusability if symbol_name is used */
- if (p->symbol_name)
- p->addr = NULL;
-}
-
-/**
- * @brief Unregistes kprobe.
- *
- * @param kp Pointer to the target kprobe.
- * @return Void.
- */
-void swap_unregister_kprobe(struct kprobe *kp)
-{
- struct kprobe *old_p, *list_p;
-
- old_p = swap_get_kprobe(kp->addr);
- if (unlikely(!old_p))
- return;
-
- if (kp != old_p) {
- list_for_each_entry_rcu(list_p, &old_p->list, list)
- if (list_p == kp)
- goto unreg_valid_kprobe;
- /* kprobe invalid */
- return;
- }
-
-unreg_valid_kprobe:
- swap_unregister_valid_kprobe(kp, old_p);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kprobe);
-
-/**
- * @brief Registers jprobe.
- *
- * @param jp Pointer to the target jprobe.
- * @return swap_register_kprobe result.
- */
-int swap_register_jprobe(struct jprobe *jp)
-{
- /* Todo: Verify probepoint is a function entry point */
- jp->kp.pre_handler = swap_setjmp_pre_handler;
- jp->kp.break_handler = swap_longjmp_break_handler;
-
- return swap_register_kprobe(&jp->kp);
-}
-EXPORT_SYMBOL_GPL(swap_register_jprobe);
-
-/**
- * @brief Unregisters jprobe.
- *
- * @param jp Pointer to the target jprobe.
- * @return Void.
- */
-void swap_unregister_jprobe(struct jprobe *jp)
-{
- swap_unregister_kprobe(&jp->kp);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_jprobe);
-
-/*
- * This kprobe pre_handler is registered with every kretprobe. When probe
- * hits it will set up the return probe.
- */
-static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
-{
- struct kretprobe *rp = container_of(p, struct kretprobe, kp);
- struct kretprobe_instance *ri;
- unsigned long flags = 0;
-
- /* TODO: consider to only swap the RA
- * after the last pre_handler fired */
- spin_lock_irqsave(&kretprobe_lock, flags);
-
- /* TODO: test - remove retprobe after func entry but before its exit */
- ri = get_free_rp_inst(rp);
- if (ri != NULL) {
- int skip = 0;
-
- ri->rp = rp;
- ri->task = current;
-
- if (rp->entry_handler)
- skip = rp->entry_handler(ri, regs);
-
- if (skip) {
- add_rp_inst(ri);
- recycle_rp_inst(ri);
- } else {
- swap_arch_prepare_kretprobe(ri, regs);
- add_rp_inst(ri);
- }
- } else {
- ++rp->nmissed;
- }
-
- spin_unlock_irqrestore(&kretprobe_lock, flags);
-
- return 0;
-}
-
-/**
- * @brief Trampoline probe handler.
- *
- * @param p Pointer to the fired kprobe.
- * @param regs Pointer to CPU registers data.
- * @return orig_ret_address
- */
-int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct kretprobe_instance *ri = NULL;
- struct hlist_head *head;
- unsigned long flags, orig_ret_address = 0;
- unsigned long trampoline_address;
-
- struct kprobe_ctlblk *kcb;
-
- struct hlist_node *tmp;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- trampoline_address = (unsigned long)&swap_kretprobe_trampoline;
-
- preempt_disable();
- kcb = swap_get_kprobe_ctlblk();
-
- spin_lock_irqsave(&kretprobe_lock, flags);
-
- /*
- * We are using different hash keys (current and mm) for finding kernel
- * space and user space probes. Kernel space probes can change mm field
- * in task_struct. User space probes can be shared between threads of
- * one process so they have different current but same mm.
- */
- head = kretprobe_inst_table_head(current);
-
-#ifdef CONFIG_X86
- regs->XREG(cs) = __KERNEL_CS | get_kernel_rpl();
- regs->EREG(ip) = trampoline_address;
- regs->ORIG_EAX_REG = 0xffffffff;
-#endif
-
- /*
- * It is possible to have multiple instances associated with a given
- * task either because an multiple functions in the call path
- * have a return probe installed on them, and/or more then one
- * return probe was registered for a target function.
- *
- * We can handle this because:
- * - instances are always inserted at the head of the list
- * - when multiple return probes are registered for the same
- * function, the first instance's ret_addr will point to the
- * real return address, and all the rest will point to
- * kretprobe_trampoline
- */
- swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
- if (ri->task != current)
- /* another task is sharing our hash bucket */
- continue;
- if (ri->rp && ri->rp->handler) {
- __get_cpu_var(swap_current_kprobe) = &ri->rp->kp;
- swap_get_kprobe_ctlblk()->kprobe_status =
- KPROBE_HIT_ACTIVE;
- ri->rp->handler(ri, regs);
- __get_cpu_var(swap_current_kprobe) = NULL;
- }
-
- orig_ret_address = (unsigned long)ri->ret_addr;
- recycle_rp_inst(ri);
- if (orig_ret_address != trampoline_address)
- /*
- * This is the real return address. Any other
- * instances associated with this task are for
- * other calls deeper on the call stack
- */
- break;
- }
- kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
- if (kcb->kprobe_status == KPROBE_REENTER)
- restore_previous_kprobe(kcb);
- else
- swap_reset_current_kprobe();
-
- spin_unlock_irqrestore(&kretprobe_lock, flags);
- swap_preempt_enable_no_resched();
-
- /*
- * By returning a non-zero value, we are telling
- * kprobe_handler() that we don't want the post_handler
- * to run (and have re-enabled preemption)
- */
-
- return (int)orig_ret_address;
-}
-
-#define SCHED_RP_NR 200
-#define COMMON_RP_NR 10
-
-static int alloc_nodes_kretprobe(struct kretprobe *rp)
-{
- int alloc_nodes;
- struct kretprobe_instance *inst;
- int i;
-
- DBPRINTF("Alloc aditional mem for retprobes");
-
- if ((unsigned long)rp->kp.addr == sched_addr) {
- rp->maxactive += SCHED_RP_NR; /* max (100, 2 * NR_CPUS); */
- alloc_nodes = SCHED_RP_NR;
- } else {
-#if 1/* def CONFIG_PREEMPT */
- rp->maxactive += max(COMMON_RP_NR, 2 * NR_CPUS);
-#else
- rp->maxacpptive += NR_CPUS;
-#endif
- alloc_nodes = COMMON_RP_NR;
- }
-
- for (i = 0; i < alloc_nodes; i++) {
- inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_ATOMIC);
- if (inst == NULL) {
- free_rp_inst(rp);
- return -ENOMEM;
- }
- INIT_HLIST_NODE(&inst->uflist);
- hlist_add_head(&inst->uflist, &rp->free_instances);
- }
-
- DBPRINTF("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr,
- (unsigned long) (*(rp->kp.addr)),
- (unsigned long) (*(rp->kp.addr + 1)),
- (unsigned long) (*(rp->kp.addr + 2)));
- return 0;
-}
-
-/**
- * @brief Registers kretprobes.
- *
- * @param rp Pointer to the target kretprobe.
- * @return 0 on success, error code on error.
- */
-int swap_register_kretprobe(struct kretprobe *rp)
-{
- int ret = 0;
- struct kretprobe_instance *inst;
- int i;
- DBPRINTF("START");
-
- rp->kp.pre_handler = pre_handler_kretprobe;
- rp->kp.post_handler = NULL;
- rp->kp.fault_handler = NULL;
- rp->kp.break_handler = NULL;
-
- /* Pre-allocate memory for max kretprobe instances */
- if ((unsigned long)rp->kp.addr == exit_addr) {
- rp->kp.pre_handler = NULL; /* not needed for do_exit */
- rp->maxactive = 0;
- } else if ((unsigned long)rp->kp.addr == do_group_exit_addr) {
- rp->kp.pre_handler = NULL;
- rp->maxactive = 0;
- } else if ((unsigned long)rp->kp.addr == sys_exit_group_addr) {
- rp->kp.pre_handler = NULL;
- rp->maxactive = 0;
- } else if ((unsigned long)rp->kp.addr == sys_exit_addr) {
- rp->kp.pre_handler = NULL;
- rp->maxactive = 0;
- } else if (rp->maxactive <= 0) {
-#if 1/* def CONFIG_PREEMPT */
- rp->maxactive = max(COMMON_RP_NR, 2 * NR_CPUS);
-#else
- rp->maxactive = NR_CPUS;
-#endif
- }
- INIT_HLIST_HEAD(&rp->used_instances);
- INIT_HLIST_HEAD(&rp->free_instances);
- for (i = 0; i < rp->maxactive; i++) {
- inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_KERNEL);
- if (inst == NULL) {
- free_rp_inst(rp);
- return -ENOMEM;
- }
- INIT_HLIST_NODE(&inst->uflist);
- hlist_add_head(&inst->uflist, &rp->free_instances);
- }
-
- DBPRINTF("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr,
- (unsigned long) (*(rp->kp.addr)),
- (unsigned long) (*(rp->kp.addr + 1)),
- (unsigned long) (*(rp->kp.addr + 2)));
- rp->nmissed = 0;
- /* Establish function entry probe point */
- ret = swap_register_kprobe(&rp->kp);
- if (ret != 0)
- free_rp_inst(rp);
-
- DBPRINTF("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr,
- (unsigned long) (*(rp->kp.addr)),
- (unsigned long) (*(rp->kp.addr + 1)),
- (unsigned long) (*(rp->kp.addr + 2)));
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(swap_register_kretprobe);
-
-static int swap_disarm_krp_inst(struct kretprobe_instance *ri);
-
-static void swap_disarm_krp(struct kretprobe *rp)
-{
- struct kretprobe_instance *ri;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
- if (swap_disarm_krp_inst(ri) != 0) {
- printk(KERN_INFO "%s (%d/%d): cannot disarm "
- "krp instance (%08lx)\n",
- ri->task->comm, ri->task->tgid, ri->task->pid,
- (unsigned long)rp->kp.addr);
- }
- }
-}
-
-
-struct unreg_krp_args {
- struct kretprobe **rps;
- size_t size;
- int rp_disarm;
-};
-
-static int __swap_unregister_kretprobes_top(void *data)
-{
- struct unreg_krp_args *args = data;
- struct kretprobe **rps = args->rps;
- size_t size = args->size;
- int rp_disarm = args->rp_disarm;
- unsigned long flags;
- const size_t end = ((size_t) 0) - 1;
-
- for (--size; size != end; --size) {
- swap_unregister_kprobe(&rps[size]->kp);
- if (rp_disarm) {
- spin_lock_irqsave(&kretprobe_lock, flags);
- swap_disarm_krp(rps[size]);
- spin_unlock_irqrestore(&kretprobe_lock, flags);
- }
- }
-
- return 0;
-}
-
-/**
- * @brief Kretprobes unregister top. Unregisters kprobes.
- *
- * @param rps Pointer to the array of pointers to the target kretprobes.
- * @param size Size of rps array.
- * @param rp_disarm Disarm flag. If set kretprobe is disarmed.
- * @return Void.
- */
-void swap_unregister_kretprobes_top(struct kretprobe **rps, size_t size,
- int rp_disarm)
-{
- struct unreg_krp_args args = {
- .rps = rps,
- .size = size,
- .rp_disarm = rp_disarm,
- };
-
- if (rp_disarm) {
- int ret;
-
- ret = stop_machine(__swap_unregister_kretprobes_top,
- &args, NULL);
- if (ret)
- pr_err("%s failed (%d)\n", __func__, ret);
- } else {
- __swap_unregister_kretprobes_top(&args);
- }
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobes_top);
-
-/**
- * @brief swap_unregister_kretprobes_top wrapper for a single kretprobe.
- *
- * @param rp Pointer to the target kretprobe.
- * @param rp_disarm Disarm flag.
- * @return Void.
- */
-void swap_unregister_kretprobe_top(struct kretprobe *rp, int rp_disarm)
-{
- swap_unregister_kretprobes_top(&rp, 1, rp_disarm);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobe_top);
-
-/**
- * @brief Kretprobe unregister bottom. Here is kretprobe memory is released.
- *
- * @param rp Pointer to the target kretprobe.
- * @return Void.
- */
-void swap_unregister_kretprobe_bottom(struct kretprobe *rp)
-{
- unsigned long flags;
- struct kretprobe_instance *ri;
-
- spin_lock_irqsave(&kretprobe_lock, flags);
-
- while ((ri = get_used_rp_inst(rp)) != NULL)
- recycle_rp_inst(ri);
- free_rp_inst(rp);
-
- spin_unlock_irqrestore(&kretprobe_lock, flags);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobe_bottom);
-
-/**
- * @brief swap_unregister_kretprobe_bottom wrapper for several kretprobes.
- *
- * @param rps Pointer to the array of the target kretprobes pointers.
- * @param size Size of rps array.
- * @return Void.
- */
-void swap_unregister_kretprobes_bottom(struct kretprobe **rps, size_t size)
-{
- const size_t end = ((size_t) 0) - 1;
-
- for (--size; size != end; --size)
- swap_unregister_kretprobe_bottom(rps[size]);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobes_bottom);
-
-/**
- * @brief Unregisters kretprobes.
- *
- * @param rpp Pointer to the array of the target kretprobes pointers.
- * @param size Size of rpp array.
- * @return Void.
- */
-void swap_unregister_kretprobes(struct kretprobe **rpp, size_t size)
-{
- swap_unregister_kretprobes_top(rpp, size, 1);
-
- if (!in_atomic())
- synchronize_sched();
-
- swap_unregister_kretprobes_bottom(rpp, size);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobes);
-
-/**
- * @brief swap_unregister_kretprobes wrapper for a single kretprobe.
- *
- * @param rp Pointer to the target kretprobe.
- * @return Void.
- */
-void swap_unregister_kretprobe(struct kretprobe *rp)
-{
- swap_unregister_kretprobes(&rp, 1);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_kretprobe);
-
-static inline void rm_task_trampoline(struct task_struct *p,
- struct kretprobe_instance *ri)
-{
- arch_set_task_pc(p, (unsigned long)ri->ret_addr);
-}
-
-static int swap_disarm_krp_inst(struct kretprobe_instance *ri)
-{
- unsigned long *tramp = (unsigned long *)&swap_kretprobe_trampoline;
- unsigned long *sp = ri->sp;
- unsigned long *found = NULL;
- int retval = -ENOENT;
-
- if (!sp) {
- unsigned long pc = arch_get_task_pc(ri->task);
-
- printk(KERN_INFO "---> [%d] %s (%d/%d): pc = %08lx, ra = %08lx, tramp= %08lx (%08lx)\n",
- task_cpu(ri->task),
- ri->task->comm, ri->task->tgid, ri->task->pid,
- pc, (long unsigned int)ri->ret_addr,
- (long unsigned int)tramp,
- (long unsigned int)(ri->rp ? ri->rp->kp.addr : NULL));
-
- /* __switch_to retprobe handling */
- if (pc == (unsigned long)tramp) {
- rm_task_trampoline(ri->task, ri);
- return 0;
- }
-
- return -EINVAL;
- }
-
- while (sp > ri->sp - RETPROBE_STACK_DEPTH) {
- if (*sp == (unsigned long)tramp) {
- found = sp;
- break;
- }
- sp--;
- }
-
- if (found) {
- printk(KERN_INFO "---> [%d] %s (%d/%d): tramp (%08lx) "
- "found at %08lx (%08lx /%+d) - %p\n",
- task_cpu(ri->task),
- ri->task->comm, ri->task->tgid, ri->task->pid,
- (long unsigned int)tramp,
- (long unsigned int)found, (long unsigned int)ri->sp,
- found - ri->sp, ri->rp ? ri->rp->kp.addr : NULL);
- *found = (unsigned long)ri->ret_addr;
- retval = 0;
- } else {
- printk(KERN_INFO "---> [%d] %s (%d/%d): tramp (%08lx) "
- "NOT found at sp = %08lx - %p\n",
- task_cpu(ri->task),
- ri->task->comm, ri->task->tgid, ri->task->pid,
- (long unsigned int)tramp,
- (long unsigned int)ri->sp,
- ri->rp ? ri->rp->kp.addr : NULL);
- }
-
- return retval;
-}
-
-static void krp_inst_flush(struct task_struct *task)
-{
- unsigned long flags;
- struct kretprobe_instance *ri;
- struct hlist_node *tmp;
- struct hlist_head *head;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- spin_lock_irqsave(&kretprobe_lock, flags);
- head = kretprobe_inst_table_head(task);
- swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
- if (ri->task == task) {
- printk("task[%u %u %s]: flush krp_inst, ret_addr=%p\n",
- task->tgid, task->pid, task->comm,
- ri->ret_addr);
- recycle_rp_inst(ri);
- }
- }
- spin_unlock_irqrestore(&kretprobe_lock, flags);
-}
-
-static int put_task_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct task_struct *t = (struct task_struct *)swap_get_karg(regs, 0);
-
- /* task has died */
- krp_inst_flush(t);
-
- return 0;
-}
-
-static struct kprobe put_task_kp = {
- .pre_handler = put_task_handler,
-};
-
-static int init_module_deps(void)
-{
- int ret;
-
- sched_addr = swap_ksyms("__switch_to");
- exit_addr = swap_ksyms("do_exit");
- sys_exit_group_addr = swap_ksyms("sys_exit_group");
- do_group_exit_addr = swap_ksyms("do_group_exit");
- sys_exit_addr = swap_ksyms("sys_exit");
-
- if (sched_addr == 0 ||
- exit_addr == 0 ||
- sys_exit_group_addr == 0 ||
- do_group_exit_addr == 0 ||
- sys_exit_addr == 0) {
- return -ESRCH;
- }
-
- ret = init_module_dependencies();
- if (ret)
- return ret;
-
- return arch_init_module_deps();
-}
-
-static int once(void)
-{
- int i, ret;
- const char *sym;
-
- sym = "module_alloc";
- module_alloc = (void *)swap_ksyms(sym);
- if (module_alloc == NULL)
- goto not_found;
-
- sym = "module_free";
- module_free = (void *)swap_ksyms(sym);
- if (module_alloc == NULL)
- goto not_found;
-
- sym = "__put_task_struct";
- put_task_kp.addr = (void *)swap_ksyms(sym);
- if (put_task_kp.addr == NULL)
- goto not_found;
-
- ret = init_module_deps();
- if (ret)
- return ret;
-
- /*
- * FIXME allocate the probe table, currently defined statically
- * initialize all list heads
- */
- for (i = 0; i < KPROBE_TABLE_SIZE; ++i) {
- INIT_HLIST_HEAD(&kprobe_table[i]);
- INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
- }
-
- return 0;
-
-not_found:
- printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
- return -ESRCH;
-}
-
-static int init_kprobes(void)
-{
- int ret;
-
- init_sm();
- atomic_set(&kprobe_count, 0);
-
- ret = swap_arch_init_kprobes();
- if (ret)
- return ret;
-
- ret = swap_register_kprobe(&put_task_kp);
- if (ret) {
- swap_arch_exit_kprobes();
- return ret;
- }
-
- return 0;
-}
-
-static void exit_kprobes(void)
-{
- swap_unregister_kprobe(&put_task_kp);
- swap_arch_exit_kprobes();
- exit_sm();
-}
-
-SWAP_LIGHT_INIT_MODULE(once, init_kprobes, exit_kprobes, NULL, NULL);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/**
- * @file kprobe/swap_kprobes.h
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM and MIPS
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) IBM Corporation, 2002, 2004
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * SWAP kprobe interface definition.
- */
-
-
-#ifndef _SWAP_KPROBES_H
-#define _SWAP_KPROBES_H
-
-#include <linux/version.h> /* LINUX_VERSION_CODE, KERNEL_VERSION() */
-#include <linux/notifier.h>
-#include <linux/percpu.h>
-#include <linux/spinlock.h>
-#include <linux/rcupdate.h>
-#include <linux/sched.h>
-#include <linux/pagemap.h>
-
-#include <swap-asm/swap_kprobes.h>
-
-
-#ifdef CONFIG_ARM
-
-#define regs_return_value(regs) ((regs)->ARM_r0)
-
-#endif
-
-
-/* kprobe_status settings */
-/** Kprobe hit active */
-#define KPROBE_HIT_ACTIVE 0x00000001
-/** Kprobe hit ss */
-#define KPROBE_HIT_SS 0x00000002
-/** Kprobe reenter */
-#define KPROBE_REENTER 0x00000004
-/** Kprobe hit ss done */
-#define KPROBE_HIT_SSDONE 0x00000008
-
-/** High word */
-#define HIWORD(x) (((x) & 0xFFFF0000) >> 16)
-/** Low word */
-#define LOWORD(x) ((x) & 0x0000FFFF)
-
-/** Invalid value */
-#define INVALID_VALUE 0xFFFFFFFF
-/** Invalid pointer */
-#define INVALID_POINTER (void *)INVALID_VALUE
-
-/** Jprobe entry */
-#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
-
-/** Retprobe stack depth */
-#define RETPROBE_STACK_DEPTH 64
-
-struct kprobe;
-struct pt_regs;
-struct kretprobe;
-struct kretprobe_instance;
-
-/**
- * @brief Kprobe pre-handler pointer.
- */
-typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *);
-
-/**
- * @brief Kprobe break handler pointer.
- */
-typedef int (*kprobe_break_handler_t) (struct kprobe *, struct pt_regs *);
-
-/**
- * @brief Kprobe post handler pointer.
- */
-typedef void (*kprobe_post_handler_t) (struct kprobe *,
- struct pt_regs *,
- unsigned long flags);
-
-/**
- * @brief Kprobe fault handler pointer.
- */
-typedef int (*kprobe_fault_handler_t) (struct kprobe *,
- struct pt_regs *,
- int trapnr);
-
-/**
- * @brief Kretprobe handler pointer.
- */
-typedef int (*kretprobe_handler_t) (struct kretprobe_instance *,
- struct pt_regs *);
-
-/**
- * @struct kprobe
- * @brief Main kprobe struct.
- */
-struct kprobe {
- struct hlist_node hlist; /**< Hash list.*/
- /** List of probes to search by instruction slot.*/
- struct hlist_node is_hlist;
- /** List of kprobes for multi-handler support.*/
- struct list_head list;
- /** Indicates that the corresponding module has been ref counted.*/
- unsigned int mod_refcounted;
- /** Count the number of times this probe was temporarily disarmed.*/
- unsigned long nmissed;
- /** Location of the probe point. */
- kprobe_opcode_t *addr;
- /** Allow user to indicate symbol name of the probe point.*/
- char *symbol_name;
- /** Offset into the symbol.*/
- unsigned int offset;
- /** Called before addr is executed.*/
- kprobe_pre_handler_t pre_handler;
- /** Called after addr is executed, unless...*/
- kprobe_post_handler_t post_handler;
- /** ... called if executing addr causes a fault (eg. page fault).*/
- kprobe_fault_handler_t fault_handler;
- /** Return 1 if it handled fault, otherwise kernel will see it.*/
- kprobe_break_handler_t break_handler;
- /** Saved opcode (which has been replaced with breakpoint).*/
- kprobe_opcode_t opcode;
- /** Copy of the original instruction.*/
- struct arch_specific_insn ainsn;
- /** Override single-step target address, may be used to redirect
- * control-flow to arbitrary address after probe point without
- * invocation of original instruction; useful for functions
- * replacement. If jprobe.entry should return address of function or
- * NULL if original function should be called.
- * Not supported for X86, not tested for MIPS. */
- kprobe_opcode_t *ss_addr[NR_CPUS];
-};
-
-/**
- * @brief Kprobe pre-entry handler pointer.
- */
-typedef unsigned long (*kprobe_pre_entry_handler_t) (void *priv_arg,
- struct pt_regs *regs);
-
-
-/**
- * @struct jprobe
- * @brief Special probe type that uses setjmp-longjmp type tricks to resume
- * execution at a specified entry with a matching prototype corresponding
- * to the probed function - a trick to enable arguments to become
- * accessible seamlessly by probe handling logic.
- * Note:
- * Because of the way compilers allocate stack space for local variables
- * etc upfront, regardless of sub-scopes within a function, this mirroring
- * principle currently works only for probes placed on function entry points.
- */
-struct jprobe {
- struct kprobe kp; /**< This probes kprobe.*/
- kprobe_opcode_t *entry; /**< Probe handling code to jump to.*/
- /** Handler which will be called before 'entry'. */
- kprobe_pre_entry_handler_t pre_entry;
- void *priv_arg; /**< Private args.*/
-};
-
-
-/**
- * @struct jprobe_instance
- * @brief Jprobe instance struct.
- */
-struct jprobe_instance {
- /* either on free list or used list */
- struct hlist_node uflist; /**< Jprobes hash list. */
- struct hlist_node hlist; /**< Jprobes hash list. */
- struct jprobe *jp; /**< Pointer to the target jprobe. */
- /** Pointer to the target task_struct. */
- struct task_struct *task;
-};
-
-
-
-
-
-/**
- * @struct kretprobe
- * @brief Function-return probe
- * Note: User needs to provide a handler function, and initialize maxactive.
- */
-struct kretprobe {
- struct kprobe kp; /**< Kprobe of this kretprobe.*/
- kretprobe_handler_t handler; /**< Handler of this kretprobe.*/
- kretprobe_handler_t entry_handler; /**< Entry handler of this kretprobe.*/
- /** The maximum number of instances of the probed function that can be
- * active concurrently. */
- int maxactive;
- /** Tracks the number of times the probed function's return was ignored,
- * due to maxactive being too low. */
- int nmissed;
- size_t data_size; /**< Size of the data. */
- /** List of this probe's free_instances. */
- struct hlist_head free_instances;
- /** List of this probe's used_instances. */
- struct hlist_head used_instances;
-
-#ifdef CONFIG_ARM
- unsigned arm_noret:1; /**< No-return flag for ARM.*/
- unsigned thumb_noret:1; /**< No-return flag for Thumb.*/
-#endif
-
-};
-
-/**
- * @struct kretprobe_instance
- * @brief Instance of kretprobe.
- */
-struct kretprobe_instance {
- /* either on free list or used list */
- struct hlist_node uflist; /**< Kretprobe hash list.*/
- struct hlist_node hlist; /**< Kretprobe hash list.*/
- struct kretprobe *rp; /**< Pointer to this instance's kretprobe.*/
- unsigned long *ret_addr; /**< Return address.*/
- unsigned long *sp; /**< Stack pointer.*/
- struct task_struct *task; /**< Pointer to the target task_struct.*/
- char data[0]; /**< Pointer to data.*/
-};
-
-
-extern void swap_kprobes_inc_nmissed_count(struct kprobe *p);
-
-/*
- * Large value for fast but memory consuming implementation
- * it is good when a lot of probes are instrumented
- */
-/* #define KPROBE_HASH_BITS 6 */
-#define KPROBE_HASH_BITS 16
-#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
-
-
-/* Get the kprobe at this addr (if any) - called with preemption disabled */
-struct kprobe *swap_get_kprobe(void *addr);
-
-
-int swap_register_kprobe(struct kprobe *p);
-void swap_unregister_kprobe(struct kprobe *p);
-
-int swap_setjmp_pre_handler(struct kprobe *, struct pt_regs *);
-int swap_longjmp_break_handler(struct kprobe *, struct pt_regs *);
-
-int swap_register_jprobe(struct jprobe *p);
-void swap_unregister_jprobe(struct jprobe *p);
-void swap_jprobe_return(void);
-
-
-int swap_register_kretprobe(struct kretprobe *rp);
-void swap_unregister_kretprobe(struct kretprobe *rp);
-void swap_unregister_kretprobes(struct kretprobe **rpp, size_t size);
-
-/*
- * use:
- * swap_unregister_kretprobe[s]_top();
- * synchronize_sched();
- * swap_unregister_kretprobe[s]_bottom();
- *
- * rp_disarm - indicates the need for restoration of the return address
- */
-void swap_unregister_kretprobe_top(struct kretprobe *rp, int rp_disarm);
-void swap_unregister_kretprobes_top(struct kretprobe **rps, size_t size,
- int rp_disarm);
-void swap_unregister_kretprobe_bottom(struct kretprobe *rp);
-void swap_unregister_kretprobes_bottom(struct kretprobe **rps, size_t size);
-
-
-int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs);
-
-
-DECLARE_PER_CPU(struct kprobe *, swap_current_kprobe);
-extern atomic_t kprobe_count;
-extern unsigned long sched_addr;
-
-struct kprobe *swap_kprobe_running(void);
-void swap_reset_current_kprobe(void);
-struct kprobe_ctlblk *swap_get_kprobe_ctlblk(void);
-
-void prepare_singlestep(struct kprobe *p, struct pt_regs *regs);
-
-#endif /* _SWAP_KPROBES_H */
-
+++ /dev/null
-/**
- * kprobe/swap_kprobes_deps.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * SWAP kprobe kernel-dependent dependencies.
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-
-#include <asm/pgtable.h>
-
-#include "swap_kprobes_deps.h"
-#include "swap_kdebug.h"
-
-
-#include <linux/slab.h>
-#include <linux/mm.h>
-
-/* kernel define 'pgd_offset_k' redefinition */
-#undef pgd_offset_k
-#define pgd_offset_k(addr) pgd_offset(init_task.active_mm, addr)
-
-#ifndef is_zero_pfn
-
-static unsigned long swap_zero_pfn ;
-
-#endif /* is_zero_pfn */
-
-static inline void *swap_kmap_atomic(struct page *page)
-{
- return kmap_atomic(page);
-}
-static inline void swap_kunmap_atomic(void *kvaddr)
-{
- kunmap_atomic(kvaddr);
-}
-
-DECLARE_MOD_FUNC_DEP(do_mmap_pgoff, unsigned long, struct file *file,
- unsigned long addr, unsigned long len, unsigned long prot,
- unsigned long flags, unsigned long pgoff,
- unsigned long *populate);
-DECLARE_MOD_DEP_WRAPPER(swap_do_mmap_pgoff,
- unsigned long,
- struct file *file, unsigned long addr,
- unsigned long len, unsigned long prot,
- unsigned long flags, unsigned long pgoff,
- unsigned long *populate)
-IMP_MOD_DEP_WRAPPER(do_mmap_pgoff, file, addr, len,
- prot, flags, pgoff, populate)
-
-EXPORT_SYMBOL_GPL(swap_do_mmap_pgoff);
-
-/* copy_to_user_page */
-#ifndef copy_to_user_page
-static DECLARE_MOD_FUNC_DEP(copy_to_user_page, void, struct vm_area_struct *vma,
- struct page *page, unsigned long uaddr, void *dst,
- const void *src, unsigned long len);
-DECLARE_MOD_DEP_WRAPPER(swap_copy_to_user_page,
- void,
- struct vm_area_struct *vma, struct page *page,
- unsigned long uaddr, void *dst, const void *src,
- unsigned long len)
-IMP_MOD_DEP_WRAPPER(copy_to_user_page, vma, page, uaddr, dst, src, len)
-#else /* copy_to_user_page */
-#define swap_copy_to_user_page copy_to_user_page
-#endif /* copy_to_user_page */
-
-
-static DECLARE_MOD_FUNC_DEP(find_extend_vma, struct vm_area_struct *,
- struct mm_struct *mm, unsigned long addr);
-
-static DECLARE_MOD_FUNC_DEP(handle_mm_fault, int, struct mm_struct *mm,
- struct vm_area_struct *vma, unsigned long address,
- unsigned int flags);
-
-static DECLARE_MOD_FUNC_DEP(get_gate_vma, struct vm_area_struct *,
- struct mm_struct *mm);
-
-#ifdef __HAVE_ARCH_GATE_AREA
-DECLARE_MOD_FUNC_DEP(in_gate_area, int, struct mm_struct *mm,
- unsigned long addr);
-#endif /* __HAVE_ARCH_GATE_AREA */
-
-static DECLARE_MOD_FUNC_DEP(in_gate_area_no_mm, int, unsigned long addr);
-
-static DECLARE_MOD_FUNC_DEP(follow_page_mask, \
- struct page *, struct vm_area_struct *vma, \
- unsigned long address, unsigned int foll_flags, \
- unsigned int *page_mask);
-DECLARE_MOD_DEP_WRAPPER(swap_follow_page_mask,
- struct page *,
- struct vm_area_struct *vma, unsigned long address,
- unsigned int foll_flags, unsigned int *page_mask)
-IMP_MOD_DEP_WRAPPER(follow_page_mask, vma, address, foll_flags, page_mask)
-
-static DECLARE_MOD_FUNC_DEP(__flush_anon_page, \
- void, struct vm_area_struct *vma, struct page *page, \
- unsigned long vmaddr);
-static DECLARE_MOD_FUNC_DEP(vm_normal_page, \
- struct page *, struct vm_area_struct *vma, \
- unsigned long addr, pte_t pte);
-
-
-static DECLARE_MOD_FUNC_DEP(put_task_struct, \
- void, struct task_struct *tsk);
-
-DECLARE_MOD_DEP_WRAPPER(swap_find_extend_vma,
- struct vm_area_struct *,
- struct mm_struct *mm, unsigned long addr)
-IMP_MOD_DEP_WRAPPER(find_extend_vma, mm, addr)
-
-DECLARE_MOD_DEP_WRAPPER(swap_handle_mm_fault,
- int,
- struct mm_struct *mm, struct vm_area_struct *vma,
- unsigned long address, unsigned int flags)
-{
- if (in_atomic())
- return VM_FAULT_ERROR | VM_FAULT_OOM;
-
- IMP_MOD_DEP_WRAPPER(handle_mm_fault, mm, vma, address, flags)
-}
-
-DECLARE_MOD_DEP_WRAPPER(swap_get_gate_vma,
- struct vm_area_struct *,
- struct mm_struct *mm)
-IMP_MOD_DEP_WRAPPER(get_gate_vma, mm)
-
-#ifdef CONFIG_HUGETLB_PAGE
-
-DECLARE_MOD_FUNC_DEP(follow_hugetlb_page, \
- long, \
- struct mm_struct *mm, struct vm_area_struct *vma, \
- struct page **pages, struct vm_area_struct **vmas, \
- unsigned long *position, unsigned long *nr_pages, \
- long i, unsigned int flags);
-DECLARE_MOD_DEP_WRAPPER(swap_follow_hugetlb_page,
- long,
- struct mm_struct *mm, struct vm_area_struct *vma,
- struct page **pages, struct vm_area_struct **vmas,
- unsigned long *position, unsigned long *nr_pages,
- long i, unsigned int flags)
-IMP_MOD_DEP_WRAPPER(follow_hugetlb_page, \
- mm, vma, pages, vmas, position, nr_pages, i, flags)
-
-#else /* CONFIG_HUGETLB_PAGE */
-#define swap_follow_hugetlb_page follow_hugetlb_page
-#endif /* CONFIG_HUGETLB_PAGE */
-
-static inline int swap_in_gate_area(struct task_struct *task,
- unsigned long addr)
-{
-#ifdef __HAVE_ARCH_GATE_AREA
- struct mm_struct *mm;
-
- if (task == NULL)
- return 0;
-
- mm = task->mm;
- IMP_MOD_DEP_WRAPPER(in_gate_area, mm, addr)
-#else /*__HAVE_ARCH_GATE_AREA */
- return in_gate_area(task, addr);
-#endif/*__HAVE_ARCH_GATE_AREA */
-}
-
-
-DECLARE_MOD_DEP_WRAPPER(swap_in_gate_area_no_mm, int, unsigned long addr)
-IMP_MOD_DEP_WRAPPER(in_gate_area_no_mm, addr)
-
-static inline int swap_in_gate_area_no_xxx(unsigned long addr)
-{
- return swap_in_gate_area_no_mm(addr);
-}
-
-DECLARE_MOD_DEP_WRAPPER(swap__flush_anon_page,
- void,
- struct vm_area_struct *vma, struct page *page,
- unsigned long vmaddr)
-IMP_MOD_DEP_WRAPPER(__flush_anon_page, vma, page, vmaddr)
-
-static inline void swap_flush_anon_page(struct vm_area_struct *vma,
- struct page *page,
- unsigned long vmaddr)
-{
-#if defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM)
- if (PageAnon(page))
- swap__flush_anon_page(vma, page, vmaddr);
-#else /* defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM) */
- flush_anon_page(vma, page, vmaddr);
-#endif /* defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM) */
-}
-
-DECLARE_MOD_DEP_WRAPPER(swap_vm_normal_page,
- struct page *,
- struct vm_area_struct *vma, unsigned long addr,
- pte_t pte)
-IMP_MOD_DEP_WRAPPER(vm_normal_page, vma, addr, pte)
-
-
-
-/**
- * @brief Initializes module dependencies.
- *
- * @return 0.
- */
-int init_module_dependencies(void)
-{
-
- INIT_MOD_DEP_VAR(handle_mm_fault, handle_mm_fault);
-
-#ifndef copy_to_user_page
- INIT_MOD_DEP_VAR(copy_to_user_page, copy_to_user_page);
-#endif /* copy_to_user_page */
-
- INIT_MOD_DEP_VAR(find_extend_vma, find_extend_vma);
- INIT_MOD_DEP_VAR(get_gate_vma, get_gate_vma);
-
-#ifdef CONFIG_HUGETLB_PAGE
- INIT_MOD_DEP_VAR(follow_hugetlb_page, follow_hugetlb_page);
-#endif
-
-#ifdef __HAVE_ARCH_GATE_AREA
- INIT_MOD_DEP_VAR(in_gate_area, in_gate_area);
-#endif
-
- INIT_MOD_DEP_VAR(follow_page_mask, follow_page_mask);
-
-
-#ifndef is_zero_pfn
- swap_zero_pfn = page_to_pfn(ZERO_PAGE(0));
-#endif /* is_zero_pfn */
-
- INIT_MOD_DEP_VAR(in_gate_area_no_mm, in_gate_area_no_mm);
-
-#if defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM)
- INIT_MOD_DEP_VAR(__flush_anon_page, __flush_anon_page);
-#endif /* defined(ARCH_HAS_FLUSH_ANON_PAGE) && defined(CONFIG_ARM) */
-
- INIT_MOD_DEP_VAR(vm_normal_page, vm_normal_page);
-
- INIT_MOD_DEP_VAR(put_task_struct, __put_task_struct);
- INIT_MOD_DEP_VAR(do_mmap_pgoff, do_mmap_pgoff);
-
- return 0;
-}
-
-
-static inline int use_zero_page(struct vm_area_struct *vma)
-{
- /*
- * We don't want to optimize FOLL_ANON for make_pages_present()
- * when it tries to page in a VM_LOCKED region. As to VM_SHARED,
- * we want to get the page from the page tables to make sure
- * that we serialize and update with any other user of that
- * mapping.
- */
- if (vma->vm_flags & (VM_LOCKED | VM_SHARED))
- return 0;
- /*
- * And if we have a fault routine, it's not an anonymous region.
- */
- return !vma->vm_ops || !vma->vm_ops->fault;
-}
-
-
-
-#ifdef __HAVE_COLOR_ZERO_PAGE
-
-static inline int swap_is_zero_pfn(unsigned long pfn)
-{
- unsigned long offset_from_zero_pfn = pfn - swap_zero_pfn;
- return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
-}
-
-#else /* __HAVE_COLOR_ZERO_PAGE */
-
-static inline int swap_is_zero_pfn(unsigned long pfn)
-{
- return pfn == swap_zero_pfn;
-}
-#endif /* __HAVE_COLOR_ZERO_PAGE */
-
-
-static inline int stack_guard_page(struct vm_area_struct *vma,
- unsigned long addr)
-{
- return stack_guard_page_start(vma, addr) ||
- stack_guard_page_end(vma, addr+PAGE_SIZE);
-}
-
-
-/**
- * @brief Gets user pages uprobe.
- *
- * @param tsk Pointer to the task_struct.
- * @param mm Pointer to the mm_struct.
- * @param start Starting address.
- * @param nr_pages Pages number.
- * @param gup_flags Flags.
- * @param pages Pointer to the array of pointers to the target page structs.
- * @param vmas Pointer to the array of pointers to the target vm_area_struct.
- * @param nonblocking Pointer to int.
- * @return negative error code on error, positive result otherwise.
- */
-long __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
- unsigned long start, unsigned long nr_pages,
- unsigned int gup_flags, struct page **pages,
- struct vm_area_struct **vmas, int *nonblocking)
-{
- long i;
- unsigned long vm_flags;
- unsigned int page_mask;
-
- if (!nr_pages)
- return 0;
-
- VM_BUG_ON(!!pages != !!(gup_flags & FOLL_GET));
-
- /*
- * Require read or write permissions.
- * If FOLL_FORCE is set, we only require the "MAY" flags.
- */
- vm_flags = (gup_flags & FOLL_WRITE) ?
- (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
- vm_flags &= (gup_flags & FOLL_FORCE) ?
- (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
-
- /*
- * If FOLL_FORCE and FOLL_NUMA are both set, handle_mm_fault
- * would be called on PROT_NONE ranges. We must never invoke
- * handle_mm_fault on PROT_NONE ranges or the NUMA hinting
- * page faults would unprotect the PROT_NONE ranges if
- * _PAGE_NUMA and _PAGE_PROTNONE are sharing the same pte/pmd
- * bitflag. So to avoid that, don't set FOLL_NUMA if
- * FOLL_FORCE is set.
- */
- if (!(gup_flags & FOLL_FORCE))
- gup_flags |= FOLL_NUMA;
-
- i = 0;
-
- do {
- struct vm_area_struct *vma;
-
- vma = swap_find_extend_vma(mm, start);
- if (!vma && swap_in_gate_area(tsk, start)) {
- unsigned long pg = start & PAGE_MASK;
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
-
- /* user gate pages are read-only */
- if (gup_flags & FOLL_WRITE)
- return i ? : -EFAULT;
- if (pg > TASK_SIZE)
- pgd = pgd_offset_k(pg);
- else
- pgd = pgd_offset_gate(mm, pg);
- BUG_ON(pgd_none(*pgd));
- pud = pud_offset(pgd, pg);
- BUG_ON(pud_none(*pud));
- pmd = pmd_offset(pud, pg);
- if (pmd_none(*pmd))
- return i ? : -EFAULT;
- VM_BUG_ON(pmd_trans_huge(*pmd));
- pte = pte_offset_map(pmd, pg);
- if (pte_none(*pte)) {
- pte_unmap(pte);
- return i ? : -EFAULT;
- }
- vma = swap_get_gate_vma(mm);
- if (pages) {
- struct page *page;
-
- page = swap_vm_normal_page(vma, start, *pte);
- if (!page) {
- if (!(gup_flags & FOLL_DUMP) &&
- swap_is_zero_pfn(pte_pfn(*pte)))
- page = pte_page(*pte);
- else {
- pte_unmap(pte);
- return i ? : -EFAULT;
- }
- }
- pages[i] = page;
- get_page(page);
- }
- pte_unmap(pte);
- page_mask = 0;
- goto next_page;
- }
-
- if (!vma ||
- (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
- !(vm_flags & vma->vm_flags))
- return i ? : -EFAULT;
-
- if (is_vm_hugetlb_page(vma)) {
- i = swap_follow_hugetlb_page(mm, vma, pages, vmas,
- &start, &nr_pages, i, gup_flags);
- continue;
- }
-
- do {
- struct page *page;
- unsigned int foll_flags = gup_flags;
- unsigned int page_increm;
-
- /*
- * If we have a pending SIGKILL, don't keep faulting
- * pages and potentially allocating memory.
- */
- if (unlikely(fatal_signal_pending(current)))
- return i ? i : -ERESTARTSYS;
-
- /* cond_resched(); */
- while (!(page = swap_follow_page_mask(vma, start,
- foll_flags, &page_mask))) {
- int ret;
- unsigned int fault_flags = 0;
-
- /* For mlock, just skip the stack guard page. */
- if (foll_flags & FOLL_MLOCK) {
- if (stack_guard_page(vma, start))
- goto next_page;
- }
- if (foll_flags & FOLL_WRITE)
- fault_flags |= FAULT_FLAG_WRITE;
- if (nonblocking)
- fault_flags |= FAULT_FLAG_ALLOW_RETRY;
- if (foll_flags & FOLL_NOWAIT)
- fault_flags |=
- (FAULT_FLAG_ALLOW_RETRY |
- FAULT_FLAG_RETRY_NOWAIT);
-
- ret = swap_handle_mm_fault(mm, vma, start,
- fault_flags);
-
- if (ret & VM_FAULT_ERROR) {
- if (ret & VM_FAULT_OOM)
- return i ? i : -ENOMEM;
- if (ret & (VM_FAULT_HWPOISON |
- VM_FAULT_HWPOISON_LARGE)) {
- if (i)
- return i;
- else if (gup_flags &
- FOLL_HWPOISON)
- return -EHWPOISON;
- else
- return -EFAULT;
- }
- if (ret & VM_FAULT_SIGBUS)
- return i ? i : -EFAULT;
- BUG();
- }
-
- if (tsk) {
- if (ret & VM_FAULT_MAJOR)
- tsk->maj_flt++;
- else
- tsk->min_flt++;
- }
-
- if (ret & VM_FAULT_RETRY) {
- if (nonblocking)
- *nonblocking = 0;
- return i;
- }
-
- /*
- * The VM_FAULT_WRITE bit tells us that
- * do_wp_page has broken COW when necessary,
- * even if maybe_mkwrite decided not to set
- * pte_write. We can thus safely do subsequent
- * page lookups as if they were reads. But only
- * do so when looping for pte_write is futile:
- * in some cases userspace may also be wanting
- * to write to the gotten user page, which a
- * read fault here might prevent (a readonly
- * page might get reCOWed by userspace write).
- */
- if ((ret & VM_FAULT_WRITE) &&
- !(vma->vm_flags & VM_WRITE))
- foll_flags &= ~FOLL_WRITE;
-
- /* cond_resched(); */
- }
- if (IS_ERR(page))
- return i ? i : PTR_ERR(page);
- if (pages) {
- pages[i] = page;
-
- swap_flush_anon_page(vma, page, start);
- flush_dcache_page(page);
- page_mask = 0;
- }
-next_page:
- if (vmas) {
- vmas[i] = vma;
- page_mask = 0;
- }
- page_increm = 1 + (~(start >> PAGE_SHIFT) & page_mask);
- if (page_increm > nr_pages)
- page_increm = nr_pages;
- i += page_increm;
- start += page_increm * PAGE_SIZE;
- nr_pages -= page_increm;
- } while (nr_pages && start < vma->vm_end);
- } while (nr_pages);
- return i;
-}
-
-
-
-/**
- * @brief Gets user pages uprobe.
- *
- * @param tsk Pointer to the task_struct.
- * @param mm Pointer to the mm_struct.
- * @param start Starting address.
- * @param len Length.
- * @param write Write flag.
- * @param force Force flag.
- * @param pages Pointer to the array of pointers to the target page structs.
- * @param vmas Pointer to the array of pointers to the target vm_area_struct.
- * @return negative error code on error, positive result otherwise.
- */
-int get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
- unsigned long start, int len, int write, int force,
- struct page **pages, struct vm_area_struct **vmas)
-{
- int flags = FOLL_TOUCH;
-
- if (pages)
- flags |= FOLL_GET;
- if (write)
- flags |= FOLL_WRITE;
- if (force)
- flags |= FOLL_FORCE;
-
- return __get_user_pages_uprobe(tsk, mm,
- start, len, flags,
- pages, vmas, NULL);
-}
-
-#define ACCESS_PROCESS_OPTIMIZATION 0
-
-#if ACCESS_PROCESS_OPTIMIZATION
-
-#define GET_STEP_X(LEN, STEP) (((LEN) >= (STEP)) ? (STEP) : (LEN) % (STEP))
-#define GET_STEP_4(LEN) GET_STEP_X((LEN), 4)
-
-static void read_data_current(unsigned long addr, void *buf, int len)
-{
- int step;
- int pos = 0;
-
- for (step = GET_STEP_4(len); len; len -= step) {
- switch (GET_STEP_4(len)) {
- case 1:
- get_user(*(u8 *)(buf + pos),
- (unsigned long *)(addr + pos));
- step = 1;
- break;
-
- case 2:
- case 3:
- get_user(*(u16 *)(buf + pos),
- (unsigned long *)(addr + pos));
- step = 2;
- break;
-
- case 4:
- get_user(*(u32 *)(buf + pos),
- (unsigned long *)(addr + pos));
- step = 4;
- break;
- }
-
- pos += step;
- }
-}
-
-/* not working */
-static void write_data_current(unsigned long addr, void *buf, int len)
-{
- int step;
- int pos = 0;
-
- for (step = GET_STEP_4(len); len; len -= step) {
- switch (GET_STEP_4(len)) {
- case 1:
- put_user(*(u8 *)(buf + pos),
- (unsigned long *)(addr + pos));
- step = 1;
- break;
-
- case 2:
- case 3:
- put_user(*(u16 *)(buf + pos),
- (unsigned long *)(addr + pos));
- step = 2;
- break;
-
- case 4:
- put_user(*(u32 *)(buf + pos),
- (unsigned long *)(addr + pos));
- step = 4;
- break;
- }
-
- pos += step;
- }
-}
-#endif
-
-/**
- * @brief Read-write task memory.
- *
- * @param tsk Pointer to the target task task_struct.
- * @param addr Address to read-write.
- * @param buf Pointer to buffer where to put-get data.
- * @param len Buffer length.
- * @param write Write flag. If 0 - reading, if 1 - writing.
- * @return Read-write size, error code on error.
- */
-int access_process_vm_atomic(struct task_struct *tsk, unsigned long addr,
- void *buf, int len, int write)
-{
- struct mm_struct *mm;
- struct vm_area_struct *vma;
- void *old_buf = buf;
- int atomic;
-
- if (len <= 0)
- return -1;
-
-#if ACCESS_PROCESS_OPTIMIZATION
- if (write == 0 && tsk == current) {
- read_data_current(addr, buf, len);
- return len;
- }
-#endif
-
- mm = tsk->mm; /* function 'get_task_mm' is to be called */
- if (!mm)
- return 0;
-
- /* FIXME: danger: write memory in atomic context */
- atomic = in_atomic();
-
- /* ignore errors, just check how much was successfully transferred */
- while (len) {
- int bytes, ret, offset;
- void *maddr;
- struct page *page = NULL;
-
- ret = get_user_pages_uprobe(tsk, mm, addr, 1,
- write, 1, &page, &vma);
-
- if (ret <= 0) {
- /*
- * Check if this is a VM_IO | VM_PFNMAP VMA, which
- * we can access using slightly different code.
- */
-#ifdef CONFIG_HAVE_IOREMAP_PROT
- vma = find_vma(mm, addr);
- if (!vma)
- break;
- if (vma->vm_ops && vma->vm_ops->access)
- ret = vma->vm_ops->access(vma, addr, buf,
- len, write);
- if (ret <= 0)
-#endif
- break;
- bytes = ret;
- } else {
- bytes = len;
- offset = addr & (PAGE_SIZE-1);
- if (bytes > PAGE_SIZE-offset)
- bytes = PAGE_SIZE-offset;
-
- maddr = atomic ? swap_kmap_atomic(page) : kmap(page);
-
- if (write) {
- swap_copy_to_user_page(vma, page, addr,
- maddr + offset,
- buf, bytes);
- set_page_dirty_lock(page);
- } else {
- copy_from_user_page(vma, page, addr,
- buf, maddr + offset,
- bytes);
- }
-
- atomic ? swap_kunmap_atomic(maddr) : kunmap(page);
- page_cache_release(page);
- }
- len -= bytes;
- buf += bytes;
- addr += bytes;
- }
-
- return buf - old_buf;
-}
-EXPORT_SYMBOL_GPL(access_process_vm_atomic);
-
-/**
- * @brief Page present.
- *
- * @param mm Pointer to the target mm_struct.
- * @param address Address.
- */
-int page_present(struct mm_struct *mm, unsigned long address)
-{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *ptep, pte;
- unsigned long pfn;
-
- pgd = pgd_offset(mm, address);
- if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
- goto out;
-
- pud = pud_offset(pgd, address);
- if (pud_none(*pud) || unlikely(pud_bad(*pud)))
- goto out;
-
- pmd = pmd_offset(pud, address);
- if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
- goto out;
-
- ptep = pte_offset_map(pmd, address);
- if (!ptep)
- goto out;
-
- pte = *ptep;
- pte_unmap(ptep);
- if (pte_present(pte)) {
- pfn = pte_pfn(pte);
- if (pfn_valid(pfn))
- return 1;
- }
-
-out:
- return 0;
-}
-EXPORT_SYMBOL_GPL(page_present);
-
+++ /dev/null
-/**
- * @file kprobe/swap_kprobes_deps.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * SWAP kprobe kernel-dependent dependencies.
- */
-
-#ifndef _SWAP_KPROBES_DEPS_H
-#define _SWAP_KPROBES_DEPS_H
-
-#include <linux/version.h> /* LINUX_VERSION_CODE, KERNEL_VERSION() */
-#include <linux/hugetlb.h>
-#include <linux/mempolicy.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <ksyms/ksyms.h>
-
-#define DECLARE_NODE_PTR_FOR_HLIST(var_name)
-#define swap_hlist_for_each_entry_rcu(tpos, pos, head, member) \
- hlist_for_each_entry_rcu(tpos, head, member)
-#define swap_hlist_for_each_entry_safe(tpos, pos, n, head, member) \
- hlist_for_each_entry_safe(tpos, n, head, member)
-#define swap_hlist_for_each_entry(tpos, pos, head, member) \
- hlist_for_each_entry(tpos, head, member)
-
-
-
-/*
- * TODO: possibly unnided
- * check and remove swap_preempt_enable_no_resched() call
- */
-
-#define swap_preempt_enable_no_resched() preempt_enable_no_resched()
-
-
-
-/* --------------------- Declaration of module dependencies ----------------- */
-
-#define DECLARE_MOD_FUNC_DEP(name, ret, ...) ret(*__ref_##name)(__VA_ARGS__)
-#define DECLARE_MOD_CB_DEP(name, ret, ...) ret(*name)(__VA_ARGS__)
-
-
-/* ---------------- Implementation of module dependencies wrappers ---------- */
-
-#define DECLARE_MOD_DEP_WRAPPER(name, ret, ...) ret name(__VA_ARGS__)
-#define IMP_MOD_DEP_WRAPPER(name, ...) \
-{ \
- return __ref_##name(__VA_ARGS__); \
-}
-
-
-/* --------------------- Module dependencies initialization ----------------- */
-
-#define INIT_MOD_DEP_VAR(dep, name) \
-{ \
- __ref_##dep = (void *) swap_ksyms(#name); \
- if (!__ref_##dep) { \
- DBPRINTF(#name " is not found! Oops. Where is it?"); \
- return -ESRCH; \
- } \
-}
-
-#define INIT_MOD_DEP_CB(dep, name) \
-{ \
- dep = (void *) swap_ksyms(#name); \
- if (!dep) { \
- DBPRINTF(#name " is not found! Oops. Where is it?"); \
- return -ESRCH; \
- } \
-}
-
-
-int init_module_dependencies(void);
-
-int access_process_vm_atomic(struct task_struct *tsk, unsigned long addr,
- void *buf, int len, int write);
-
-#define read_proc_vm_atomic(tsk, addr, buf, len) \
- access_process_vm_atomic(tsk, addr, buf, len, 0)
-#define write_proc_vm_atomic(tsk, addr, buf, len) \
- access_process_vm_atomic(tsk, addr, buf, len, 1)
-int page_present(struct mm_struct *mm, unsigned long addr);
-
-unsigned long swap_do_mmap_pgoff(struct file *file, unsigned long addr,
- unsigned long len, unsigned long prot,
- unsigned long flags, unsigned long pgoff,
- unsigned long *populate);
-
-
-#endif /* _SWAP_KPROBES_DEPS_H */
+++ /dev/null
-/**
- * kprobe/swap_slots.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) IBM Corporation, 2002, 2004
- * Copyright (C) Samsung Electronics, 2006-2012
- *
- * @section DESCRIPTION
- *
- * SWAP slots implementation.
- */
-
-
-#include <linux/module.h>
-#include <linux/rculist.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-
-#include "swap_slots.h"
-#include "swap_kprobes_deps.h"
-
-
-/**
- * @struct chunk
- * @brief Chunk of memory for trampolines.
- * @var chunk::data
- * Chunk data.
- * @var chunk::first_available
- * Index of the first available block.
- * @var chunk::count_available
- * Count of the blocks.
- * @var chunk::lock
- * Chunk's lock.
- * @var chunk::size
- * Count of the blocks in chunk.
- * @var chunk::index
- * Pointer to allocated memory.
- */
-struct chunk {
- unsigned long *data;
- unsigned long first_available;
- unsigned long count_available;
-
- spinlock_t lock;
- unsigned long size;
- unsigned long *index;
-};
-
-/**
- * @struct fixed_alloc
- * @brief Item of fixed allocs list.
- * @var fixed_alloc::hlist
- * Fixed alloc hash list node.
- * @var fixed_alloc::chunk
- * Chunk.
- */
-struct fixed_alloc {
- struct hlist_node hlist;
- struct chunk chunk;
-};
-
-static int chunk_init(struct chunk *chunk, void *data,
- size_t size, size_t size_block)
-{
- unsigned long i;
- unsigned long *p;
-
- spin_lock_init(&chunk->lock);
- chunk->data = (unsigned long *)data;
- chunk->first_available = 0;
- chunk->count_available = size / size_block;
- chunk->size = chunk->count_available;
-
- chunk->index = kmalloc(sizeof(*chunk->index)*chunk->count_available,
- GFP_ATOMIC);
-
- if (chunk->index == NULL) {
- pr_err("%s: failed to allocate memory\n", __func__);
- return -ENOMEM;
- }
-
- p = chunk->index;
- for (i = 0; i != chunk->count_available; ++p)
- *p = ++i;
-
- return 0;
-}
-
-static void chunk_uninit(struct chunk *chunk)
-{
- kfree(chunk->index);
-}
-
-static void *chunk_allocate(struct chunk *chunk, size_t size_block)
-{
- unsigned long *ret;
-
- if (!chunk->count_available)
- return NULL;
-
- spin_lock(&chunk->lock);
- ret = chunk->data + chunk->first_available*size_block;
- chunk->first_available = chunk->index[chunk->first_available];
- --chunk->count_available;
- spin_unlock(&chunk->lock);
-
- return ret;
-}
-
-static void chunk_deallocate(struct chunk *chunk, void *p, size_t size_block)
-{
- unsigned long idx = ((unsigned long *)p - chunk->data)/size_block;
-
- spin_lock(&chunk->lock);
- chunk->index[idx] = chunk->first_available;
- chunk->first_available = idx;
- ++chunk->count_available;
- spin_unlock(&chunk->lock);
-}
-
-static inline int chunk_check_ptr(struct chunk *chunk, void *p, size_t size)
-{
- if ((chunk->data <= (unsigned long *)p) &&
- ((chunk->data + size/sizeof(chunk->data)) > (unsigned long *)p))
- return 1;
-
- return 0;
-}
-
-static inline int chunk_free(struct chunk *chunk)
-{
- return (chunk->count_available == chunk->size);
-}
-
-static struct fixed_alloc *create_fixed_alloc(struct slot_manager *sm)
-{
- int ret;
- void *data;
- struct fixed_alloc *fa;
-
- fa = kmalloc(sizeof(*fa), GFP_ATOMIC);
- if (fa == NULL)
- return NULL;
-
- data = sm->alloc(sm);
- if (data == NULL)
- goto free_fa;
-
- ret = chunk_init(&fa->chunk, data,
- PAGE_SIZE / sizeof(unsigned long), sm->slot_size);
- if (ret)
- goto free_sm;
-
- return fa;
-
-free_sm:
- sm->free(sm, data);
-free_fa:
- kfree(fa);
- return NULL;
-}
-
-static void free_fixed_alloc(struct slot_manager *sm, struct fixed_alloc *fa)
-{
- chunk_uninit(&fa->chunk);
- sm->free(sm, fa->chunk.data);
- kfree(fa);
-}
-
-
-/**
- * @brief Allocates slot for slot manager.
- *
- * @param[in,out] sm Slot manager that should be filled.
- * @return Pointer to allocated slot.
- */
-void *swap_slot_alloc(struct slot_manager *sm)
-{
- void *free_slot;
- struct fixed_alloc *fa;
- DECLARE_NODE_PTR_FOR_HLIST(pos);
-
- swap_hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
- free_slot = chunk_allocate(&fa->chunk, sm->slot_size);
- if (free_slot)
- return free_slot;
- }
-
- fa = create_fixed_alloc(sm);
- if (fa == NULL)
- return NULL;
-
- INIT_HLIST_NODE(&fa->hlist);
- hlist_add_head_rcu(&fa->hlist, &sm->page_list);
-
- return chunk_allocate(&fa->chunk, sm->slot_size);
-}
-EXPORT_SYMBOL_GPL(swap_slot_alloc);
-
-/**
- * @brief Releases allocated slot.
- *
- * @param sm Pointer to the target slot manager.
- * @param slot Pointer to the target slot.
- * @return Void.
- */
-void swap_slot_free(struct slot_manager *sm, void *slot)
-{
- struct fixed_alloc *fa;
- DECLARE_NODE_PTR_FOR_HLIST(pos);
-
- if (slot == NULL)
- return;
-
- swap_hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
- if (!chunk_check_ptr(&fa->chunk, slot, PAGE_SIZE))
- continue;
-
- chunk_deallocate(&fa->chunk, slot, sm->slot_size);
-
- if (chunk_free(&fa->chunk)) {
- hlist_del_rcu(&fa->hlist);
- free_fixed_alloc(sm, fa);
- }
-
- return;
- }
-
- panic("%s: slot=%p is not data base\n", __func__, slot);
-}
-EXPORT_SYMBOL_GPL(swap_slot_free);
+++ /dev/null
-/**
- * @file kprobe/swap_slots.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
- * Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) IBM Corporation, 2002, 2004
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * SWAP slots interface declaration.
- */
-
-#ifndef _SWAP_SLOTS_H
-#define _SWAP_SLOTS_H
-
-#include <linux/types.h>
-
-/**
- * @struct slot_manager
- * @brief Manage slots.
- * @var slot_manager::slot_size
- * Size of the slot.
- * @var slot_manager::alloc
- * Memory allocation callback.
- * @var slot_manager::free
- * Memory release callback.
- * @var slot_manager::page_list
- * List of pages.
- * @var slot_manager::data
- * Slot manager data. task_struct pointer usually stored here.
- */
-struct slot_manager {
- unsigned long slot_size; /* FIXME: allocated in long (4 byte) */
- void *(*alloc)(struct slot_manager *sm);
- void (*free)(struct slot_manager *sm, void *ptr);
- struct hlist_head page_list;
- void *data;
-};
-
-void *swap_slot_alloc(struct slot_manager *sm);
-void swap_slot_free(struct slot_manager *sm, void *slot);
-
-#endif /* _SWAP_SLOTS_H */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_ks_features.o
-swap_ks_features-y := ks_features.o \
- ks_map.o \
- file_ops.o \
- ksf_msg.o
+++ /dev/null
-/**
- * ks_features/features_data.c
- * @author Vyacheslav Cherkashin: SWAP ks_features implement
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * SWAP kernel features
- */
-
-
-#include "ksf_msg.h"
-#include "syscall_list.h"
-
-
-/**
- * @struct feature
- * Feature description.
- * @var feature::cnt
- * Syscalls count.
- * @var feature::feature_list
- * Pointer to feature's syscall list.
- * @var feature::type
- * Featue subtype.
- * @var feature::enable
- * Is feature enable.
- */
-struct feature {
- size_t cnt;
- enum syscall_id *feature_list;
- enum probe_t type;
-
- unsigned enable:1;
-};
-
-/**
- * @def X
- * X-macros for syscall list.
- */
-#define X(name, args) id_##name
-/**
- * @enum syscall_id
- * Syscall list
- */
-enum syscall_id {
- SYSCALL_LIST
-};
-#undef X
-
-static enum syscall_id id_none[] = {};
-
-static enum syscall_id id_file[] = {
- id_sys_acct,
- id_sys_mount,
- id_sys_umount,
- id_sys_truncate,
-/* TODO:
- * id_sys_stat,
- */
- id_sys_statfs,
- id_sys_statfs64,
-/* TODO:
- * id_sys_lstat,
- */
- id_sys_stat64,
- id_sys_fstat64,
- id_sys_lstat64,
- id_sys_truncate64,
- id_sys_ftruncate64,
- id_sys_setxattr,
- id_sys_getxattr,
- id_sys_listxattr,
- id_sys_removexattr,
- id_sys_chroot,
- id_sys_mknod,
- id_sys_link,
- id_sys_symlink,
- id_sys_unlink,
- id_sys_rename,
- id_sys_chmod,
- id_sys_readlink,
- id_sys_creat,
- id_sys_open,
- id_sys_access,
- id_sys_chown,
- id_sys_chown16,
- id_sys_utime,
- id_sys_utimes,
- id_sys_pread64,
- id_sys_pwrite64,
- id_sys_preadv,
- id_sys_pwritev,
- id_sys_getcwd,
- id_sys_mkdir,
- id_sys_chdir,
- id_sys_rmdir,
- id_sys_swapon,
- id_sys_swapoff,
- id_sys_uselib,
- id_sys_mknodat,
- id_sys_mkdirat,
- id_sys_unlinkat,
- id_sys_symlinkat,
- id_sys_linkat,
- id_sys_renameat,
- id_sys_futimesat,
- id_sys_faccessat,
- id_sys_fchmodat,
- id_sys_fchownat,
- id_sys_openat,
-/* TODO:
- * id_sys_newfstatat,
- */
- id_sys_readlinkat,
- id_sys_utimensat,
- id_sys_fanotify_mark,
- id_sys_execve,
- id_sys_name_to_handle_at,
- id_sys_open_by_handle_at
-};
-
-static enum syscall_id id_ipc[] = {
- id_sys_msgget,
- id_sys_msgsnd,
- id_sys_msgrcv,
- id_sys_msgctl,
- id_sys_semget,
- id_sys_semop,
- id_sys_semctl,
- id_sys_semtimedop,
- id_sys_shmat,
- id_sys_shmget,
- id_sys_shmdt,
- id_sys_shmctl,
- id_sys_ipc
-};
-
-static enum syscall_id id_net[] = {
- id_sys_shutdown,
- id_sys_sendfile,
- id_sys_sendfile64,
- id_sys_setsockopt,
- id_sys_getsockopt,
- id_sys_bind,
- id_sys_connect,
- id_sys_accept,
- id_sys_accept4,
- id_sys_getsockname,
- id_sys_getpeername,
- id_sys_send,
- id_sys_sendto,
- id_sys_sendmsg,
- id_sys_sendmmsg,
- id_sys_recv,
- id_sys_recvfrom,
- id_sys_recvmsg,
- id_sys_recvmmsg,
- id_sys_socket,
- id_sys_socketpair,
- id_sys_socketcall,
- id_sys_listen
-};
-
-static enum syscall_id id_process[] = {
- id_sys_exit,
- id_sys_exit_group,
- id_sys_wait4,
- id_sys_waitid,
-/* TODO:
- * id_sys_waitpid,
- */
- id_sys_rt_tgsigqueueinfo,
- id_sys_unshare,
- id_sys_fork,
- id_sys_vfork,
-/* TODO: add support CONFIG_CLONE_BACKWARDS
- * id_sys_clone,
- * id_sys_clone,
- */
- id_sys_execve
-};
-
-static enum syscall_id id_signal[] = {
- id_sys_sigpending,
- id_sys_sigprocmask,
-/* TODO:
- * id_sys_sigaltstack,
- */
-/* TODO: add support CONFIG_OLD_SIGSUSPEND and CONFIG_OLD_SIGSUSPEND3
- * id_sys_sigsuspend,
- * id_sys_sigsuspend,
- */
- id_sys_rt_sigsuspend,
- id_sys_sigaction,
- id_sys_rt_sigaction,
- id_sys_rt_sigprocmask,
- id_sys_rt_sigtimedwait,
- id_sys_rt_tgsigqueueinfo,
- id_sys_kill,
- id_sys_tgkill,
-/* TODO:
- * id_sys_signal,
- */
- id_sys_pause,
- id_sys_signalfd,
- id_sys_signalfd4
-};
-
-static enum syscall_id id_desc[] = {
- id_sys_fgetxattr,
- id_sys_flistxattr,
- id_sys_fremovexattr,
- id_sys_fadvise64_64,
- id_sys_pipe2,
- id_sys_dup3,
- id_sys_sendfile,
- id_sys_sendfile64,
- id_sys_preadv,
- id_sys_pwritev,
- id_sys_epoll_create1,
- id_sys_epoll_ctl,
- id_sys_epoll_wait,
- id_sys_epoll_pwait,
- id_sys_inotify_init,
- id_sys_inotify_init1,
- id_sys_inotify_add_watch,
- id_sys_inotify_rm_watch,
- id_sys_mknodat,
- id_sys_mkdirat,
- id_sys_unlinkat,
- id_sys_symlinkat,
- id_sys_linkat,
- id_sys_renameat,
- id_sys_futimesat,
- id_sys_faccessat,
- id_sys_fchmodat,
- id_sys_fchownat,
- id_sys_openat,
-/* TODO:
- * id_sys_newfstatat,
- */
- id_sys_readlinkat,
- id_sys_utimensat,
- id_sys_splice,
- id_sys_vmsplice,
- id_sys_tee,
- id_sys_signalfd,
- id_sys_signalfd4,
- id_sys_timerfd_create,
- id_sys_timerfd_settime,
- id_sys_timerfd_gettime,
- id_sys_eventfd,
- id_sys_eventfd2,
- id_sys_fallocate,
- id_sys_pselect6,
- id_sys_ppoll,
- id_sys_fanotify_init,
- id_sys_fanotify_mark,
- id_sys_syncfs,
- id_sys_mmap_pgoff,
- id_sys_old_mmap,
- id_sys_name_to_handle_at,
- id_sys_setns
-};
-
-/**
- * @def CREATE_FEATURE
- * Feature initialization.
- */
-#define CREATE_FEATURE(x, _type) \
-{ \
- .cnt = sizeof(x) / sizeof(enum syscall_id), \
- .feature_list = x, \
- .type = _type, \
- .enable = 0 \
-}
-
-static struct feature features[] = {
- CREATE_FEATURE(id_none, PT_KS_NONE),
- CREATE_FEATURE(id_file, PT_KS_FILE),
- CREATE_FEATURE(id_ipc, PT_KS_IPC),
- CREATE_FEATURE(id_process, PT_KS_PROCESS),
- CREATE_FEATURE(id_signal, PT_KS_SIGNAL),
- CREATE_FEATURE(id_net, PT_KS_NETWORK),
- CREATE_FEATURE(id_desc, PT_KS_DESC)
-};
-
-/**
- * @enum
- * Defines feature_cnt.
- */
-enum {
- feature_cnt = sizeof(features) / sizeof(struct feature)
-};
-
-static int feature_index(struct feature *f)
-{
- return f - features;
-}
+++ /dev/null
-#include <linux/module.h>
-#include <linux/dcache.h>
-#include <linux/percpu.h>
-#include <linux/namei.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/file.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <kprobe/swap_kprobes.h>
-#include <writer/event_filter.h>
-#include "ks_map.h"
-#include "ksf_msg.h"
-#include "file_ops.h"
-
-#define FOPS_PREFIX "[FILE_OPS] "
-
-#define PT_FILE 0x4 /* probe type FILE(04) */
-
-/* path buffer size */
-enum { PATH_LEN = 512 };
-
-struct file_probe {
- int id;
- const char *args;
- int subtype;
- struct kretprobe rp;
-};
-
-#define to_file_probe(_rp) container_of(_rp, struct file_probe, rp)
-
-/* common private data */
-struct file_private {
- struct dentry *dentry;
-};
-
-/* open/creat private data */
-struct open_private {
- int dfd;
- const char __user *name;
- int ret;
-};
-
-/* locks private data */
-struct flock_private {
- struct dentry *dentry;
- int subtype;
-};
-
-#define DECLARE_HANDLER(_name) \
- int _name(struct kretprobe_instance *, struct pt_regs *)
-
-/* generic handlers forward declaration */
-static DECLARE_HANDLER(generic_entry_handler);
-static DECLARE_HANDLER(generic_ret_handler);
-/* open/creat handlers */
-static DECLARE_HANDLER(open_entry_handler);
-static DECLARE_HANDLER(open_ret_handler);
-/* lock handlers */
-static DECLARE_HANDLER(lock_entry_handler);
-static DECLARE_HANDLER(lock_ret_handler);
-/* filp_close helper handlers */
-static DECLARE_HANDLER(filp_close_entry_handler);
-static DECLARE_HANDLER(filp_close_ret_handler);
-
-#define FILE_OPS_OPEN_LIST \
- X(sys_open, sdd), \
- X(sys_openat, dsdd), \
- X(sys_creat, sd)
-
-#define FILE_OPS_CLOSE_LIST \
- X(sys_close, d)
-
-#define FILE_OPS_READ_LIST \
- X(sys_read, dpd), \
- X(sys_readv, dpd), \
- X(sys_pread64, dpxx), \
- X(sys_preadv, dpxxx)
-
-#define FILE_OPS_WRITE_LIST \
- X(sys_write, dpd), \
- X(sys_writev, dpd), \
- X(sys_pwrite64, dpxx), \
- X(sys_pwritev, dpxxx)
-
-#define FILE_OPS_LOCK_LIST \
- X(sys_fcntl, ddd), \
- X(sys_fcntl64, ddd), \
- X(sys_flock, dd)
-
-#define FILE_OPS_LIST \
- FILE_OPS_OPEN_LIST, \
- FILE_OPS_CLOSE_LIST, \
- FILE_OPS_READ_LIST, \
- FILE_OPS_WRITE_LIST, \
- FILE_OPS_LOCK_LIST
-
-#define X(_name, _args) \
- id_##_name
-enum {
- FILE_OPS_LIST
-};
-#undef X
-
-#define __FILE_PROBE_INITIALIZER(_name, _args, _subtype, _dtype, _entry, _ret) \
- { \
- .id = id_##_name, \
- .args = #_args, \
- .subtype = _subtype, \
- .rp = { \
- .kp.symbol_name = #_name, \
- .data_size = sizeof(_dtype), \
- .entry_handler = _entry, \
- .handler = _ret, \
- } \
- }
-
-static struct file_probe fprobes[] = {
-#define X(_name, _args) \
- [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_OPEN, \
- struct open_private, \
- open_entry_handler, \
- open_ret_handler)
- FILE_OPS_OPEN_LIST,
-#undef X
-
-#define X(_name, _args) \
- [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_CLOSE, \
- struct file_private, \
- generic_entry_handler, \
- generic_ret_handler)
- FILE_OPS_CLOSE_LIST,
-#undef X
-
-#define X(_name, _args) \
- [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_READ, \
- struct file_private, \
- generic_entry_handler, \
- generic_ret_handler)
- FILE_OPS_READ_LIST,
-#undef X
-
-#define X(_name, _args) \
- [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_WRITE, \
- struct file_private, \
- generic_entry_handler, \
- generic_ret_handler)
- FILE_OPS_WRITE_LIST,
-#undef X
-
-#define X(_name, _args) \
- [id_##_name] = __FILE_PROBE_INITIALIZER(_name, _args, FOPS_OTHER, \
- struct flock_private, \
- lock_entry_handler, \
- lock_ret_handler)
- FILE_OPS_LOCK_LIST
-#undef X
-};
-
-static void *fops_key_func(void *);
-static int fops_cmp_func(void *, void *);
-
-/* percpu buffer to hold the filepath inside handlers */
-static DEFINE_PER_CPU(char[PATH_LEN], __path_buf);
-
-/* map to hold 'interesting' files */
-static DEFINE_MAP(__map, fops_key_func, fops_cmp_func);
-static DEFINE_RWLOCK(__map_lock);
-
-/* enabled/disabled flag */
-static int fops_enabled;
-static DEFINE_MUTEX(fops_lock);
-
-/* GET/PUT debug stuff */
-static int file_get_put_balance;
-static int dentry_get_put_balance;
-
-/* helper probe */
-static struct kretprobe filp_close_krp = {
- .kp.symbol_name = "filp_close",
- .data_size = 0,
- .entry_handler = filp_close_entry_handler,
- .handler = filp_close_ret_handler
-};
-
-/* should be called only from handlers (with preemption disabled) */
-static inline char *fops_path_buf(void)
-{
- return __get_cpu_var(__path_buf);
-}
-
-static inline unsigned fops_dcount(const struct dentry *dentry)
-{
- return dentry->d_count;
-}
-
-/* kernel function args */
-#define fops_karg(_type, _regs, _idx) ((_type)swap_get_karg(_regs, _idx))
-/* syscall args */
-#define fops_sarg(_type, _regs, _idx) ((_type)swap_get_sarg(_regs, _idx))
-/* retval */
-#define fops_ret(_type, _regs) ((_type)regs_return_value(_regs))
-
-#define F_ADDR(_rp) ((unsigned long)(_rp)->kp.addr) /* function address */
-#define R_ADDR(_ri) ((unsigned long)(_ri)->ret_addr) /* return adress */
-
-static void *fops_key_func(void *data)
-{
- /* use ((struct dentry *)data)->d_inode pointer as map key to handle
- * symlinks/hardlinks the same way as the original file */
- return data;
-}
-
-static int fops_cmp_func(void *key_a, void *key_b)
-{
- return key_a - key_b;
-}
-
-static inline struct map *__get_map(void)
-{
- return &__map;
-}
-
-static inline struct map *get_map_read(void)
-{
- read_lock(&__map_lock);
-
- return __get_map();
-}
-
-static inline void put_map_read(struct map *map)
-{
- read_unlock(&__map_lock);
-}
-
-static inline struct map *get_map_write(void)
-{
- write_lock(&__map_lock);
-
- return __get_map();
-}
-
-static inline void put_map_write(struct map *map)
-{
- write_unlock(&__map_lock);
-}
-
-static struct file *__fops_fget(int fd)
-{
- struct file *file;
-
- file = fget(fd);
- if (IS_ERR_OR_NULL(file))
- file = NULL;
- else
- file_get_put_balance++;
-
- return file;
-}
-
-static void __fops_fput(struct file *file)
-{
- file_get_put_balance--;
- fput(file);
-}
-
-static struct dentry *__fops_dget(struct dentry *dentry)
-{
- dentry_get_put_balance++;
-
- return dget(dentry);
-}
-
-static void __fops_dput(struct dentry *dentry)
-{
- dentry_get_put_balance--;
- dput(dentry);
-}
-
-static int fops_dinsert(struct dentry *dentry)
-{
- struct map *map;
- int ret;
-
- map = get_map_write();
- ret = insert(map, __fops_dget(dentry));
- put_map_write(map);
-
- if (ret)
- __fops_dput(dentry);
-
- /* it's ok if dentry is already inserted */
- return ret == -EEXIST ? 0 : ret;
-}
-
-static struct dentry *fops_dsearch(struct dentry *dentry)
-{
- struct dentry *found;
- struct map *map;
-
- map = get_map_read();
- found = search(map, map->key_f(dentry));
- put_map_read(map);
-
- return found;
-}
-
-static struct dentry *fops_dremove(struct dentry *dentry)
-{
- struct dentry *removed;
- struct map *map;
-
- map = get_map_write();
- removed = remove(map, map->key_f(dentry));
- put_map_write(map);
-
- if (removed)
- __fops_dput(removed);
-
- return removed;
-}
-
-static int fops_fcheck(struct task_struct *task, struct file *file)
-{
- struct dentry *dentry;
-
- if (!task || !file)
- return -EINVAL;
-
- dentry = file->f_dentry;
-
- /* check if it is a regular file */
- if (!S_ISREG(dentry->d_inode->i_mode))
- return -EBADF;
-
- if (check_event(task))
- /* it is 'our' task: just add the dentry to the map */
- return fops_dinsert(dentry) ? : -EAGAIN;
- else
- /* not 'our' task: check if the file is 'interesting' */
- return fops_dsearch(dentry) ? 0 : -ESRCH;
-}
-
-static char *fops_fpath(struct file *file, char *buf, int buflen)
-{
- char *filename;
-
- path_get(&file->f_path);
- filename = d_path(&file->f_path, buf, buflen);
- path_put(&file->f_path);
-
- if (IS_ERR_OR_NULL(filename)) {
- printk(FOPS_PREFIX "d_path FAILED: %ld\n", PTR_ERR(filename));
- buf[0] = '\0';
- filename = buf;
- }
-
- return filename;
-}
-
-static int generic_entry_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct kretprobe *rp = ri->rp;
-
- if (rp) {
- struct file_probe *fprobe = to_file_probe(rp);
- struct file_private *priv = (struct file_private *)ri->data;
- int fd = fops_sarg(int, regs, 0);
- struct file *file = __fops_fget(fd);
-
- if (fops_fcheck(current, file) == 0) {
- char *buf = fops_path_buf();
-
- ksf_msg_file_entry(fd, fprobe->subtype,
- fops_fpath(file, buf, PATH_LEN));
-
- priv->dentry = file->f_dentry;
- } else {
- priv->dentry = NULL;
- }
-
- if (file)
- __fops_fput(file);
- }
-
- return 0;
-}
-
-static int generic_ret_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct kretprobe *rp = ri->rp;
- struct file_private *priv = (struct file_private *)ri->data;
-
- if (rp && priv->dentry)
- ksf_msg_file_exit(regs, 'x');
-
- return 0;
-}
-
-static int open_private_init(const char *args, struct pt_regs *regs,
- struct open_private *priv)
-{
- int ret = 0;
-
- switch (args[0]) {
- case 'd': /* file name: relative to fd */
- if (args[1] != 's') {
- ret = -EINVAL;
- break;
- }
- priv->dfd = fops_sarg(int, regs, 0);
- priv->name = fops_sarg(const char __user *, regs, 1);
- break;
- case 's': /* file name: absolute or relative to CWD */
- priv->dfd = AT_FDCWD;
- priv->name = fops_sarg(const char __user *, regs, 0);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- priv->ret = ret;
-
- return ret;
-}
-
-static int open_entry_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct kretprobe *rp = ri->rp;
-
- if (rp) {
- struct file_probe *fprobe = to_file_probe(rp);
- struct open_private *priv = (struct open_private *)ri->data;
-
- open_private_init(fprobe->args, regs, priv);
- /* FIXME entry event will be sent in open_ret_handler: cannot
- * perform a file lookup in atomic context */
- }
-
- return 0;
-}
-
-static int open_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
- struct kretprobe *rp = ri->rp;
- struct open_private *priv = (struct open_private *)ri->data;
-
- if (rp && priv->ret == 0) {
- struct file_probe *fprobe = to_file_probe(rp);
- int fd = fops_ret(int, regs);
- struct file *file = __fops_fget(fd);
-
- if (fops_fcheck(current, file) == 0) {
- char *buf = fops_path_buf();
- const char *path = fops_fpath(file, buf, PATH_LEN);
-
- ksf_msg_file_entry_open(fd, fprobe->subtype,
- path, priv->name);
- ksf_msg_file_exit(regs, 'x');
- }
-
- if (file)
- __fops_fput(file);
- }
-
- return 0;
-}
-
-/* wrapper for 'struct flock*' data */
-struct lock_arg {
- int type;
- int whence;
- s64 start;
- s64 len;
-};
-
-/* TODO copy_from_user */
-#define __lock_arg_init(_type, _regs, _arg) \
- do { \
- _type __user *flock = fops_sarg(_type __user *, _regs, 2); \
- _arg->type = flock->l_type; \
- _arg->whence = flock->l_whence; \
- _arg->start = flock->l_start; \
- _arg->len = flock->l_len; \
- } while (0)
-
-static int lock_arg_init(int id, struct pt_regs *regs, struct lock_arg *arg)
-{
- unsigned int cmd = fops_sarg(unsigned int, regs, 1);
- int ret = 0;
-
- switch (id) {
- case id_sys_fcntl:
- if (cmd == F_SETLK || cmd == F_SETLKW)
- __lock_arg_init(struct flock, regs, arg);
- else
- ret = -EINVAL;
- break;
- case id_sys_fcntl64:
- if (cmd == F_SETLK64 || cmd == F_SETLKW64)
- __lock_arg_init(struct flock64, regs, arg);
- else if (cmd == F_SETLK || cmd == F_SETLKW)
- __lock_arg_init(struct flock, regs, arg);
- else
- ret = -EINVAL;
- break;
- case id_sys_flock: /* TODO is it really needed? */
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int lock_entry_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct kretprobe *rp = ri->rp;
-
- if (rp) {
- struct file_probe *fprobe = to_file_probe(rp);
- struct flock_private *priv = (struct flock_private *)ri->data;
- int fd = fops_sarg(int, regs, 0);
- struct file *file = __fops_fget(fd);
-
- if (fops_fcheck(current, file) == 0) {
- int subtype = fprobe->subtype;
- struct lock_arg arg;
- char *buf, *filepath;
-
- buf = fops_path_buf();
- filepath = fops_fpath(file, buf, PATH_LEN);
-
- if (lock_arg_init(fprobe->id, regs, &arg) == 0) {
- subtype = arg.type == F_UNLCK ?
- FOPS_LOCK_RELEASE :
- FOPS_LOCK_START;
- ksf_msg_file_entry_lock(fd, subtype, filepath,
- arg.type, arg.whence,
- arg.start, arg.len);
- } else {
- ksf_msg_file_entry(fd, subtype, filepath);
- }
-
- priv->dentry = file->f_dentry;
- priv->subtype = subtype;
- } else {
- priv->dentry = NULL;
- }
-
- if (file)
- __fops_fput(file);
- }
-
- return 0;
-}
-
-static int lock_ret_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct kretprobe *rp = ri->rp;
- struct flock_private *priv = (struct flock_private *)ri->data;
-
- if (rp && priv->dentry)
- ksf_msg_file_exit(regs, 'x');
-
- return 0;
-}
-
-static int filp_close_entry_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct kretprobe *rp = ri->rp;
- struct file *file = fops_karg(struct file *, regs, 0);
-
- if (rp && file && file_count(file)) {
- struct dentry *dentry = file->f_dentry;
-
- /* release the file if it is going to be removed soon */
- if (dentry && fops_dcount(dentry) == 2)
- fops_dremove(dentry);
- }
-
- return 0;
-}
-
-static int filp_close_ret_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- return 0;
-}
-
-static void fops_unregister_probes(struct file_probe *fprobes, int cnt)
-{
- int i = cnt;
-
- /* probes are unregistered in reverse order */
- while (--i >= 0) {
- struct kretprobe *rp = &fprobes[i].rp;
-
- swap_unregister_kretprobe(rp);
- printk(FOPS_PREFIX "'%s/%08lx' kretprobe unregistered (%d)\n",
- rp->kp.symbol_name, F_ADDR(rp), i);
- }
-
- /* unregister helper probes */
- swap_unregister_kretprobe(&filp_close_krp);
-}
-
-static int fops_register_probes(struct file_probe *fprobes, int cnt)
-{
- struct kretprobe *rp = &filp_close_krp;
- int ret, i = 0;
-
- /* register helper probes */
- ret = swap_register_kretprobe(rp);
- if (ret)
- goto fail;
-
- /* register syscalls */
- for (i = 0; i < cnt; i++) {
- rp = &fprobes[i].rp;
-
- if (!rp->entry_handler)
- rp->entry_handler = generic_entry_handler;
-
- if (!rp->handler)
- rp->handler = generic_ret_handler;
-
- ret = swap_register_kretprobe(rp);
- if (ret)
- goto fail_unreg;
-
- printk(FOPS_PREFIX "'%s/%08lx' kretprobe registered (%d)\n",
- rp->kp.symbol_name, F_ADDR(rp), i);
- }
-
- return 0;
-
-fail_unreg:
- fops_unregister_probes(fprobes, i);
-
-fail:
- printk(FOPS_PREFIX "Failed to register probe: %s\n",
- rp->kp.symbol_name);
-
- return ret;
-}
-
-static char *__fops_dpath(struct dentry *dentry, char *buf, int buflen)
-{
- static const char *NA = "N/A";
- char *filename = dentry_path_raw(dentry, buf, buflen);
-
- if (IS_ERR_OR_NULL(filename)) {
- printk(FOPS_PREFIX "dentry_path_raw FAILED: %ld\n",
- PTR_ERR(filename));
- strncpy(buf, NA, buflen);
- filename = buf;
- }
-
- return filename;
-}
-
-/* just a simple wrapper for passing to clear function */
-static int __fops_dput_wrapper(void *data, void *arg)
-{
- static char buf[PATH_LEN]; /* called under write lock => static is ok */
- struct dentry *dentry = data;
- struct inode *inode = dentry->d_inode;
-
- printk(FOPS_PREFIX "Releasing dentry(%p/%p/%d): %s\n",
- dentry, inode, inode ? inode->i_nlink : 0,
- __fops_dpath(dentry, buf, PATH_LEN));
- __fops_dput(dentry);
-
- return 0;
-}
-
-bool file_ops_is_init(void)
-{
- return fops_enabled;
-}
-
-int file_ops_init(void)
-{
- int ret = -EINVAL;
-
- mutex_lock(&fops_lock);
-
- if (fops_enabled) {
- printk(FOPS_PREFIX "Handlers already enabled\n");
- goto unlock;
- }
-
- ret = fops_register_probes(fprobes, ARRAY_SIZE(fprobes));
- if (ret == 0)
- fops_enabled = 1;
-
-unlock:
- mutex_unlock(&fops_lock);
-
- return ret;
-}
-
-void file_ops_exit(void)
-{
- struct map *map;
-
- mutex_lock(&fops_lock);
-
- if (!fops_enabled) {
- printk(FOPS_PREFIX "Handlers not enabled\n");
- goto unlock;
- }
-
- /* 1. unregister probes */
- fops_unregister_probes(fprobes, ARRAY_SIZE(fprobes));
-
- /* 2. clear the map */
- map = get_map_write();
- printk(FOPS_PREFIX "Clearing map: entries(%d)\n", map->size);
- clear(map, __fops_dput_wrapper, NULL);
- WARN(file_get_put_balance, "File GET/PUT balance: %d\n",
- file_get_put_balance);
- WARN(dentry_get_put_balance, "Dentry GET/PUT balance: %d\n",
- dentry_get_put_balance);
- put_map_write(map);
-
- /* 3. drop the flag */
- fops_enabled = 0;
-
-unlock:
- mutex_unlock(&fops_lock);
-}
+++ /dev/null
-#ifndef __FILE_OPS__
-#define __FILE_OPS__
-
-#include <linux/types.h>
-
-bool file_ops_is_init(void);
-int file_ops_init(void);
-void file_ops_exit(void);
-
-#endif /* __FILE_OPS__ */
+++ /dev/null
-/**
- * ks_features/ks_features.c
- * @author Vyacheslav Cherkashin: SWAP ks_features implement
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * SWAP kernel features
- */
-
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <ksyms/ksyms.h>
-#include <kprobe/swap_kprobes.h>
-#include <master/swap_initializer.h>
-#include <writer/event_filter.h>
-#include "ksf_msg.h"
-#include "ks_features.h"
-#include "syscall_list.h"
-#include "features_data.c"
-#include "file_ops.h"
-
-
-/**
- * @struct ks_probe
- * @brief Kernel-space probe. Struct used as a container of syscall probes.
- * @var ks_probe::rp
- * Pointer to kretprobe.
- * @var ks_probe::counter
- * Installed probes counter.
- * @var ks_probe::args
- * Pointer to args format string.
- * @var ks_probe::type
- * Probe sub type.
- */
-struct ks_probe {
- struct kretprobe rp;
- int counter;
- char *args;
- int type;
-};
-
-#define CREATE_RP(name) \
-{ \
- .entry_handler = NULL, \
- .handler = NULL \
-}
-
-#define X(name, args) #name
-static const char *const syscall_name[] = {
- SYSCALL_LIST
-};
-#undef X
-
-/**
- * @enum
- * Syscall name count defenition
- */
-enum {
- syscall_name_cnt = sizeof(syscall_name) / sizeof(char *)
-};
-
-
-#define X(name, args__) \
-{ \
- .rp = CREATE_RP(name), \
- .counter = 0, \
- .args = #args__, \
- .type = PT_KS_NONE \
-}
-
-static struct ks_probe ksp[] = {
- SYSCALL_LIST
-};
-#undef X
-
-static const char *get_sys_name(size_t id)
-{
- return syscall_name[id];
-}
-
-static int get_counter(size_t id)
-{
- return ksp[id].counter;
-}
-
-static void inc_counter(size_t id)
-{
- ++ksp[id].counter;
-}
-
-static void dec_counter(size_t id)
-{
- --ksp[id].counter;
-}
-
-/* ========================= HANDLERS ========================= */
-static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
- struct kretprobe *rp = ri->rp;
-
- if (rp && check_event(current)) {
- struct ks_probe *ksp = container_of(rp, struct ks_probe, rp);
- const char *fmt = ksp->args;
- const unsigned long addr = (unsigned long)ksp->rp.kp.addr;
- enum probe_t type = ksp->type;
-
- ksf_msg_entry(regs, addr, type, fmt);
- }
-
- return 0;
-}
-
-static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
- struct kretprobe *rp = ri->rp;
-
- if (rp && check_event(current)) {
- struct ks_probe *ksp = container_of(rp, struct ks_probe, rp);
- const unsigned long func_addr = (unsigned long)rp->kp.addr;
- const unsigned long ret_addr = (unsigned long)ri->ret_addr;
- enum probe_t type = ksp->type;
-
- ksf_msg_exit(regs, func_addr, ret_addr, type, 'x');
- }
-
- return 0;
-}
-/* ========================= HANDLERS ========================= */
-
-
-
-
-/* ====================== SWITCH_CONTEXT ======================= */
-static int switch_entry_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- if (check_event(current))
- ksf_switch_entry(regs);
-
- return 0;
-}
-
-static int switch_ret_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- if (check_event(current))
- ksf_switch_exit(regs);
-
- return 0;
-}
-
-/**
- * @var switch_rp
- * Kretprobe for scheduler.
- */
-struct kretprobe switch_rp = {
- .entry_handler = switch_entry_handler,
- .handler = switch_ret_handler
-};
-
-static DEFINE_MUTEX(mutex_sc_enable);
-static int sc_enable;
-
-/**
- * @brief Get scheduler address.
- *
- * @return 0 on success, negative error code on error.
- */
-int init_switch_context(void)
-{
- unsigned long addr;
-
- addr = swap_ksyms("__switch_to");
- if (addr == 0) {
- printk(KERN_INFO "ERROR: not found '__switch_to'\n");
- return -EINVAL;
- }
-
- switch_rp.kp.addr = (kprobe_opcode_t *)addr;
-
- return 0;
-}
-
-/**
- * @brief Unregisters probe on context switching.
- *
- * @return Void.
- */
-void exit_switch_context(void)
-{
- if (sc_enable)
- swap_unregister_kretprobe(&switch_rp);
-}
-
-static int register_switch_context(void)
-{
- int ret = -EINVAL;
-
- mutex_lock(&mutex_sc_enable);
- if (sc_enable) {
- printk(KERN_INFO "switch context profiling is already run!\n");
- goto unlock;
- }
-
- ret = swap_register_kretprobe(&switch_rp);
- if (ret == 0)
- sc_enable = 1;
-
-unlock:
- mutex_unlock(&mutex_sc_enable);
-
- return ret;
-}
-
-static int unregister_switch_context(void)
-{
- int ret = 0;
-
- mutex_lock(&mutex_sc_enable);
- if (sc_enable == 0) {
- printk(KERN_INFO "switch context profiling is not running!\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- swap_unregister_kretprobe(&switch_rp);
-
- sc_enable = 0;
-unlock:
- mutex_unlock(&mutex_sc_enable);
-
- return ret;
-}
-/* ====================== SWITCH_CONTEXT ======================= */
-
-
-
-
-
-static int register_syscall(size_t id)
-{
- int ret;
- printk(KERN_INFO "register_syscall: %s\n", get_sys_name(id));
-
- if (ksp[id].rp.kp.addr == NULL)
- return 0;
-
- ksp[id].rp.entry_handler = entry_handler;
- ksp[id].rp.handler = ret_handler;
-
- ret = swap_register_kretprobe(&ksp[id].rp);
-
- return ret;
-}
-
-
-static int unregister_syscall(size_t id)
-{
- printk(KERN_INFO "unregister_syscall: %s\n", get_sys_name(id));
-
- if (ksp[id].rp.kp.addr == NULL)
- return 0;
-
- swap_unregister_kretprobe(&ksp[id].rp);
-
- return 0;
-}
-
-static int unregister_multiple_syscalls(size_t *id_p, size_t cnt)
-{
- struct kretprobe **rpp;
- const size_t end = ((size_t) 0) - 1;
- size_t i = 0, id;
- int ret = 0;
-
- if (cnt == 1)
- return unregister_syscall(id_p[0]);
-
- --cnt;
-
- rpp = kmalloc(GFP_KERNEL, sizeof(*rpp) * cnt);
- if (rpp == NULL) {
- for (; cnt != end; --cnt) {
- ret = unregister_syscall(id_p[cnt]);
- if (ret)
- return ret;
- }
- return ret;
- }
-
- for (; cnt != end; --cnt) {
- id = id_p[cnt];
- if (ksp[id].rp.kp.addr != NULL) {
- rpp[i] = &ksp[id].rp;
- ++i;
- }
- }
-
- swap_unregister_kretprobes(rpp, i);
- kfree(rpp);
-
- return 0;
-}
-
-static void set_pst(struct feature *f, size_t id)
-{
- ksp[id].type |= f->type;
-}
-
-static void unset_pst(struct feature *f, size_t id)
-{
- ksp[id].type &= !f->type;
-}
-
-static void do_uninstall_features(struct feature *f, size_t i)
-{
- int ret;
- size_t *id_p;
- size_t id;
- size_t cnt = 0;
- const size_t end = ((size_t) 0) - 1;
-
- id_p = kmalloc(GFP_KERNEL, sizeof(id) * (i + 1));
- /* NULL check is below in loop */
-
- for (; i != end; --i) {
- id = f->feature_list[i];
-
- if (get_counter(id) == 0) {
- printk(KERN_INFO "syscall %s not installed\n",
- get_sys_name(id));
- kfree(id_p);
- BUG();
- }
-
- dec_counter(id);
-
- if (get_counter(id) == 0) {
- if (id_p != NULL) {
- id_p[cnt] = id;
- ++cnt;
- } else {
- ret = unregister_syscall(id);
- if (ret)
- printk(KERN_INFO "syscall %s uninstall error, ret=%d\n",
- get_sys_name(id), ret);
- }
- }
-
- unset_pst(f, id);
- }
-
- if (id_p != NULL) {
- unregister_multiple_syscalls(id_p, cnt);
- kfree(id_p);
- }
-}
-
-static int do_install_features(struct feature *f)
-{
- int ret;
- size_t i, id;
-
- for (i = 0; i < f->cnt; ++i) {
- id = f->feature_list[i];
- set_pst(f, id);
-
- if (get_counter(id) == 0) {
- ret = register_syscall(id);
- if (ret) {
- printk(KERN_INFO "syscall %s install error, ret=%d\n",
- get_sys_name(id), ret);
-
- do_uninstall_features(f, --i);
- return ret;
- }
- }
-
- inc_counter(id);
- }
-
- return 0;
-}
-
-static DEFINE_MUTEX(mutex_features);
-
-static int install_features(struct feature *f)
-{
- int ret = 0;
-
- mutex_lock(&mutex_features);
- if (f->enable) {
- printk(KERN_INFO "energy profiling is already run!\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- ret = do_install_features(f);
-
- f->enable = 1;
-unlock:
- mutex_unlock(&mutex_features);
- return ret;
-}
-
-static int uninstall_features(struct feature *f)
-{
- int ret = 0;
-
- mutex_lock(&mutex_features);
- if (f->enable == 0) {
- printk(KERN_INFO "feature[%d] is not running!\n",
- feature_index(f));
- ret = -EINVAL;
- goto unlock;
- }
- do_uninstall_features(f, f->cnt - 1);
- f->enable = 0;
-unlock:
- mutex_unlock(&mutex_features);
-
- return ret;
-}
-
-static struct feature *get_feature(enum feature_id id)
-{
- if (id < 0 || id >= (int)feature_cnt)
- return NULL;
-
- return &features[id];
-}
-
-/**
- * @brief Sets probes related to specified feature.
- *
- * @param id Feature id.
- * @return 0 on success, negative error code on error.
- */
-int set_feature(enum feature_id id)
-{
- struct feature *f;
- int ret;
-
- switch (id) {
- case FID_SYSFILE_ACTIVITY:
- ret = file_ops_init();
- break;
- case FID_SWITCH:
- ret = register_switch_context();
- break;
- default:
- f = get_feature(id);
- ret = f ? install_features(f) : -EINVAL;
- break;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(set_feature);
-
-/**
- * @brief Unsets probes related to specified feature.
- *
- * @param id Feature id.
- * @return 0 on success, negative error code on error.
- */
-int unset_feature(enum feature_id id)
-{
- struct feature *f;
- int ret = 0;
-
- switch (id) {
- case FID_SYSFILE_ACTIVITY:
- file_ops_exit();
- break;
- case FID_SWITCH:
- ret = unregister_switch_context();
- break;
- default:
- f = get_feature(id);
- ret = f ? uninstall_features(f) : -EINVAL;
- break;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(unset_feature);
-
-static int init_syscall_features(void)
-{
- size_t i;
- unsigned long addr, ni_syscall;
- const char *name;
-
- ni_syscall = swap_ksyms("sys_ni_syscall");
-
- for (i = 0; i < syscall_name_cnt; ++i) {
- name = get_sys_name(i);
- addr = swap_ksyms(name);
- if (addr == 0) {
- printk(KERN_INFO "INFO: %s() not found\n", name);
- } else if (ni_syscall == addr) {
- printk(KERN_INFO "INFO: %s is not install\n", name);
- addr = 0;
- }
-
- ksp[i].rp.kp.addr = (kprobe_opcode_t *)addr;
- }
-
- return 0;
-}
-
-static void uninit_syscall_features(void)
-{
- size_t id;
-
- for (id = 0; id < syscall_name_cnt; ++id) {
- if (get_counter(id) > 0)
- unregister_syscall(id);
- }
-}
-
-
-static int once(void)
-{
- int ret;
-
- ret = init_switch_context();
- if (ret)
- return ret;
-
- ret = init_syscall_features();
-
- return ret;
-}
-
-static void core_uninit(void)
-{
- uninit_syscall_features();
- exit_switch_context();
-
- if (file_ops_is_init())
- file_ops_exit();
-}
-
-SWAP_LIGHT_INIT_MODULE(once, NULL, core_uninit, NULL, NULL);
-
-MODULE_LICENSE("GPL");
-
-/* debug */
-static void print_feature(struct feature *f)
-{
- size_t i;
-
- for (i = 0; i < f->cnt; ++i)
- printk(KERN_INFO " feature[%3u]: %s\n", i,
- get_sys_name(f->feature_list[i]));
-}
-
-/**
- * @brief Prints features.
- *
- * @return Void.
- */
-void print_features(void)
-{
- int i;
-
- printk(KERN_INFO "print_features:\n");
- for (i = 0; i < feature_cnt; ++i) {
- printk(KERN_INFO "feature: %d\n", i);
- print_feature(&features[i]);
- }
-}
-
-/**
- * @brief Prints all syscalls.
- *
- * @return Void.
- */
-void print_all_syscall(void)
-{
- int i;
-
- printk(KERN_INFO "SYSCALL:\n");
- for (i = 0; i < syscall_name_cnt; ++i)
- printk(KERN_INFO " [%2d] %s\n",
- get_counter(i), get_sys_name(i));
-}
-/* debug */
+++ /dev/null
-/**
- * @file ks_features/ks_features.h
- * @author Vyacheslav Cherkashin: SWAP ks_features implement
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * SWAP kernel features interface declaration.
- */
-
-
-#ifndef _KS_FEATURES_H
-#define _KS_FEATURES_H
-
-/**
- * @enum feature_id
- * Features ids
- */
-enum feature_id {
- FID_FILE = 1, /**< File probes */
- FID_IPC = 2, /**< Hz probes */
- FID_PROCESS = 3, /**< Process probes */
- FID_SIGNAL = 4, /**< Signal probes */
- FID_NET = 5, /**< Network probes */
- FID_DESC = 6, /**< Description probes */
- FID_SWITCH = 7, /**< Switch context probes */
- FID_SYSFILE_ACTIVITY = 8 /**< System file activity */
-};
-
-int set_feature(enum feature_id id);
-int unset_feature(enum feature_id id);
-
-/* debug */
-void print_features(void);
-void print_all_syscall(void);
-/* debug */
-
-#endif /* _KS_FEATURES_H */
+++ /dev/null
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include "ks_map.h"
-
-struct entry {
- struct rb_node node;
- void *data;
-};
-
-static inline void *entry_data(struct entry *entry)
-{
- return entry->data;
-}
-
-static struct entry *alloc_entry(struct map *map, void *data)
-{
- struct entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
-
- if (entry) {
- entry->data = data;
- RB_CLEAR_NODE(&entry->node);
- }
-
- return entry;
-}
-
-static void *free_entry(struct map *map, struct entry *entry)
-{
- void *data = entry_data(entry);
-
- kfree(entry);
-
- return data;
-}
-
-static struct entry *__search(struct map *map, void *key)
-{
- struct rb_root *root = &map->root;
- struct rb_node *node = root->rb_node;
- key_func_t key_f = map->key_f;
- cmp_func_t cmp_f = map->cmp_f;
-
- while (node) {
- struct entry *entry = rb_entry(node, struct entry, node);
- int result = cmp_f(key_f(entry_data(entry)), key);
-
- if (result < 0)
- node = node->rb_left;
- else if (result > 0)
- node = node->rb_right;
- else
- return entry;
- }
-
- return NULL;
-}
-
-void *search(struct map *map, void *key)
-{
- struct entry *entry = __search(map, key);
-
- return entry ? entry_data(entry) : NULL;
-}
-
-static void *__remove(struct map *map, struct entry *entry)
-{
- struct rb_root *root = &map->root;
-
- rb_erase(&entry->node, root);
- RB_CLEAR_NODE(&entry->node);
- map->size--;
-
- return free_entry(map, entry);
-}
-
-void *remove(struct map *map, void *key)
-{
- struct entry *entry = __search(map, key);
-
- /* Removes entry from the tree but does not free the data */
- return entry ? __remove(map, entry) : NULL;
-}
-
-static void *__replace(struct map *map, struct entry *old, struct entry *new)
-{
- struct rb_root *root = &map->root;
-
- rb_replace_node(&old->node, &new->node, root);
-
- return free_entry(map, old);
-}
-
-void *replace(struct map *map, void *data)
-{
- struct entry *old, *new;
-
- old = __search(map, map->key_f(data));
- if (old) {
- new = alloc_entry(map, data);
- if (!new)
- return ERR_PTR(-ENOMEM);
-
- return __replace(map, old, new);
- }
-
- return ERR_PTR(-ESRCH);
-}
-
-int insert(struct map *map, void *data)
-{
- struct rb_root *root = &map->root;
- struct rb_node **new = &(root->rb_node), *parent = NULL;
- key_func_t key_f = map->key_f;
- cmp_func_t cmp_f = map->cmp_f;
- void *key = key_f(data);
- struct entry *entry;
-
- /* Figure out where to put new node */
- while (*new) {
- struct entry *this = rb_entry(*new, struct entry, node);
- int result = cmp_f(key_f(entry_data(this)), key);
-
- parent = *new;
- if (result < 0)
- new = &((*new)->rb_left);
- else if (result > 0)
- new = &((*new)->rb_right);
- else /* entry already inserted */
- return -EEXIST;
- }
-
- entry = alloc_entry(map, data);
- if (!entry)
- return -ENOMEM;
-
- /* Add new node and rebalance tree. */
- rb_link_node(&entry->node, parent, new);
- rb_insert_color(&entry->node, root);
- map->size++;
-
- return 0;
-}
-
-int for_each_entry(struct map *map, act_func_t func, void *arg)
-{
- struct rb_root *root = &map->root;
- struct rb_node *node = rb_first(root);
- int ret = 0;
-
- while (node) {
- struct entry *entry = rb_entry(node, struct entry, node);
-
- /* Stop iteration if actor returns non zero */
- ret = func(entry_data(entry), arg);
- if (ret)
- break;
-
- node = rb_next(node);
- }
-
- return ret;
-}
-
-int for_each_entry_reverse(struct map *map, act_func_t func, void *arg)
-{
- struct rb_root *root = &map->root;
- struct rb_node *node = rb_last(root);
- int ret = 0;
-
- while (node) {
- struct entry *entry = rb_entry(node, struct entry, node);
-
- /* Stop iteration if actor returns non zero */
- ret = func(entry_data(entry), arg);
- if (ret)
- break;
-
- node = rb_prev(node);
- }
-
- return ret;
-}
-
-void clear(struct map *map, act_func_t destructor, void *arg)
-{
- struct rb_root *root = &map->root;
- struct rb_node *node = root->rb_node;
-
- while (node) {
- struct entry *entry = rb_entry(node, struct entry, node);
- void *data = __remove(map, entry);
-
- /* call the data 'destructor' if supplied */
- if (destructor)
- destructor(data, arg);
-
- node = root->rb_node;
- }
-
- WARN(map->size, "ks_map size: %d\n", map->size);
- map->root = RB_ROOT;
-}
+++ /dev/null
-#ifndef __KS_MAP__
-#define __KS_MAP__
-
-#include <linux/rbtree.h>
-
-typedef void *(*key_func_t)(void *);
-typedef int (*cmp_func_t)(void *, void *);
-typedef int (*act_func_t)(void *, void *);
-
-struct map {
- struct rb_root root;
- int size;
- key_func_t key_f;
- cmp_func_t cmp_f;
-};
-
-#define __MAP_INITIALIZER(_key_f, _cmp_f) \
- { \
- .root = RB_ROOT, \
- .size = 0, \
- .key_f = _key_f, \
- .cmp_f = _cmp_f \
- }
-
-#define DEFINE_MAP(_name, _key_f, _cmp_f) \
- struct map _name = __MAP_INITIALIZER(_key_f, _cmp_f)
-
-void *search(struct map *map, void *key);
-void *remove(struct map *map, void *key);
-void *replace(struct map *map, void *data);
-int insert(struct map *map, void *data);
-int for_each_entry(struct map *map, act_func_t func, void *arg);
-int for_each_entry_reverse(struct map *map, act_func_t act, void *arg);
-void clear(struct map *map, act_func_t destructor, void *arg);
-
-#endif /* __KS_MAP__ */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/sched.h>
-#include <writer/swap_msg.h>
-#include <writer/kernel_operations.h>
-#include "ksf_msg.h"
-
-
-#define KSF_PREFIX KERN_INFO "[KSF] "
-
-
-
-
-
-/* ============================================================================
- * = MSG_SYSCALL_* (ENTRY/EXIT) =
- * ============================================================================
- */
-struct msg_sys_header {
- u32 pid;
- u32 tid;
- u32 probe_type;
- u64 pc_addr;
- u64 caller_pc_addr;
- u32 cpu_num;
-} __packed;
-
-struct msg_sys_entry {
- struct msg_sys_header h;
- u32 cnt_args;
- char args[0];
-} __packed;
-
-struct msg_sys_exit {
- struct msg_sys_header h;
- char ret_val[0];
-} __packed;
-
-
-static void pack_header(struct msg_sys_header *h, unsigned long func_addr,
- unsigned long ret_addr, enum probe_t type)
-{
- struct task_struct *task = current;
-
- h->pid = task->tgid;
- h->tid = task->pid;
- h->probe_type = (u32)type;
- h->pc_addr = func_addr;
- h->caller_pc_addr = ret_addr;
- h->cpu_num = smp_processor_id();
-}
-
-static void pack_entry_header(struct msg_sys_entry *e, struct pt_regs *regs,
- unsigned long func_addr, enum probe_t type,
- const char *fmt)
-{
- pack_header(&e->h, func_addr, get_regs_ret_func(regs), type);
- e->cnt_args = strlen(fmt);
-}
-
-static void pack_exit_header(struct msg_sys_exit *e, unsigned long func_addr,
- unsigned long ret_addr, enum probe_t type)
-{
- pack_header(&e->h, func_addr, ret_addr, type);
-}
-
-void ksf_msg_entry(struct pt_regs *regs, unsigned long func_addr,
- enum probe_t type, const char *fmt)
-{
- int ret;
- struct swap_msg *m;
- struct msg_sys_entry *ent;
- size_t size;
-
- m = swap_msg_get(MSG_SYSCALL_ENTRY);
-
- ent = swap_msg_payload(m);
- pack_entry_header(ent, regs, func_addr, type, fmt);
-
- size = swap_msg_size(m) - sizeof(*ent);
- ret = swap_msg_pack_args(ent->args, size, fmt, regs);
- if (ret < 0) {
- printk(KSF_PREFIX "ERROR: arguments packing, ret=%d\n", ret);
- goto put_msg;
- }
-
- swap_msg_flush(m, sizeof(*ent) + ret);
-
-put_msg:
- swap_msg_put(m);
-}
-
-void ksf_msg_exit(struct pt_regs *regs, unsigned long func_addr,
- unsigned long ret_addr, enum probe_t type, char ret_type)
-{
- int ret;
- struct swap_msg *m;
- struct msg_sys_exit *ext;
- size_t size;
-
- m = swap_msg_get(MSG_SYSCALL_EXIT);
-
- ext = swap_msg_payload(m);
- pack_exit_header(ext, func_addr, ret_addr, type);
-
- size = swap_msg_size(m) - sizeof(*ext);
- ret = swap_msg_pack_ret_val(ext->ret_val, size, ret_type, regs);
- if (ret < 0) {
- printk(KSF_PREFIX "ERROR: ret value packing, ret=%d\n", ret);
- goto put_msg;
- }
-
- swap_msg_flush(m, sizeof(*ext) + ret);
-
-put_msg:
- swap_msg_put(m);
-}
-
-
-
-
-
-/* ============================================================================
- * = MSG_FILE_FUNCTION_* (ENTRY/EXIT) =
- * ============================================================================
- */
-struct msg_file_entry {
- u32 pid;
- u32 tid;
- u32 fd;
- u32 event_type;
- char file_path[0];
-} __packed;
-
-enum file_info {
- FI_GENIRAL = 0,
- FI_OPEN = 1,
- FI_LOCK = 2
-};
-
-static int pack_file_entry_head(void *data, size_t size, enum file_info info,
- int fd, enum file_api_t api, const char *path)
-{
- struct msg_file_entry *ent = (struct msg_file_entry *)data;
- struct task_struct *task = current;
- size_t len, old_size = size;
-
- ent->pid = task->tgid;
- ent->tid = task->pid;
- ent->fd = fd;
- ent->event_type = api;
-
- size -= sizeof(*ent);
- len = strlen(path);
- if (size < len + 1)
- return -ENOMEM;
-
- memcpy(ent->file_path, path, len);
- ent->file_path[len] = '\0';
-
- size -= len + 1;
- data += old_size - size;
-
- if (size < 4)
- return -ENOMEM;
-
- *((u32 *)data) = (u32)info;
- size -= 4;
-
- return old_size - size;
-}
-
-
-
-void ksf_msg_file_entry(int fd, enum file_api_t api, const char *path)
-{
- int ret;
- void *p;
- size_t size;
- struct swap_msg *m;
-
- m = swap_msg_get(MSG_FILE_FUNCTION_ENTRY);
- p = swap_msg_payload(m);
- size = swap_msg_size(m);
-
- ret = pack_file_entry_head(p, size, FI_GENIRAL, fd, api, path);
- if (ret < 0) {
- printk(KSF_PREFIX "buffer is too small\n");
- goto put_msg;
- }
-
- swap_msg_flush(m, ret);
-
-put_msg:
- swap_msg_put(m);
-}
-
-void ksf_msg_file_entry_open(int fd, enum file_api_t api, const char *path,
- const char __user *ofile)
-{
- long n;
- int ret;
- void *p;
- size_t size;
- struct swap_msg *m;
-
- m = swap_msg_get(MSG_FILE_FUNCTION_ENTRY);
- p = swap_msg_payload(m);
- size = swap_msg_size(m);
-
- ret = pack_file_entry_head(p, size, FI_OPEN, fd, api, path);
- if (ret < 0) {
- printk(KSF_PREFIX "buffer is too small\n");
- goto put_msg;
- }
-
- size -= ret;
- p += ret;
-
- n = strncpy_from_user(p, ofile, size);
- if (n < 0) {
- printk(KSF_PREFIX "cannot copy ofile\n");
- goto put_msg;
- }
-
- swap_msg_flush(m, ret + n + 1);
-
-put_msg:
- swap_msg_put(m);
-}
-
-struct lock_arg {
- u32 type;
- u32 whence;
- u64 start;
- u64 len;
-} __packed;
-
-void ksf_msg_file_entry_lock(int fd, enum file_api_t api, const char *path,
- int type, int whence, s64 start, s64 len)
-{
- int ret;
- void *p;
- size_t size;
- struct swap_msg *m;
- struct lock_arg *arg;
-
- m = swap_msg_get(MSG_FILE_FUNCTION_ENTRY);
- p = swap_msg_payload(m);
- size = swap_msg_size(m);
-
- ret = pack_file_entry_head(p, size, FI_LOCK, fd, api, path);
- if (ret < 0) {
- printk(KSF_PREFIX "buffer is too small\n");
- goto put_msg;
- }
-
- size -= ret;
- p += ret;
-
- if (size < sizeof(*arg)) {
- printk(KSF_PREFIX "buffer is too small\n");
- goto put_msg;
- }
-
- arg = (struct lock_arg *)p;
- arg->type = (u32)type;
- arg->whence = (u32)whence;
- arg->start = (u64)start;
- arg->len = (u64)len;
-
- swap_msg_flush(m, ret + sizeof(*arg));
-
-put_msg:
- swap_msg_put(m);
-}
-
-
-struct msg_file_exit {
- u32 pid;
- u32 tid;
- char ret_val[0];
-} __packed;
-
-void ksf_msg_file_exit(struct pt_regs *regs, char ret_type)
-{
- struct task_struct *task = current;
- int ret;
- struct swap_msg *m;
- struct msg_file_exit *ext;
- size_t size;
-
- m = swap_msg_get(MSG_FILE_FUNCTION_EXIT);
-
- ext = swap_msg_payload(m);
- ext->pid = task->tgid;
- ext->tid = task->pid;
-
- size = swap_msg_size(m) - sizeof(*ext);
- ret = swap_msg_pack_ret_val(ext->ret_val, size, ret_type, regs);
- if (ret < 0) {
- printk(KSF_PREFIX "ERROR: ret value packing, ret=%d\n", ret);
- goto put_msg;
- }
-
- swap_msg_flush(m, sizeof(*ext) + ret);
-
-put_msg:
- swap_msg_put(m);
-}
-
-
-
-
-
-/* ============================================================================
- * = MSG_FILE_FUNCTION_* (ENTRY/EXIT) =
- * ============================================================================
- */
-struct msg_context_switch {
- u64 pc_addr;
- u32 pid;
- u32 tid;
- u32 cpu_num;
-} __packed;
-
-static void context_switch(struct pt_regs *regs, enum swap_msg_id id)
-{
- struct task_struct *task = current;
- struct swap_msg *m;
- struct msg_context_switch *mcs;
- void *p;
-
- m = swap_msg_get(id);
- p = swap_msg_payload(m);
-
- mcs = p;
- mcs->pc_addr = 0;
- mcs->pid = task->tgid;
- mcs->tid = task->pid;
- mcs->cpu_num = smp_processor_id();
-
- swap_msg_flush_wakeupoff(m, sizeof(*mcs));
- swap_msg_put(m);
-}
-
-void ksf_switch_entry(struct pt_regs *regs)
-{
- context_switch(regs, MSG_CONTEXT_SWITCH_ENTRY);
-}
-
-void ksf_switch_exit(struct pt_regs *regs)
-{
- context_switch(regs, MSG_CONTEXT_SWITCH_EXIT);
-}
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _KSF_MSG_H
-#define _KSF_MSG_H
-
-
-enum probe_t {
- PT_KS_NONE = 0x00,
- PT_KS_FILE = 0x01,
- PT_KS_IPC = 0x02,
- PT_KS_PROCESS = 0x04,
- PT_KS_SIGNAL = 0x08,
- PT_KS_NETWORK = 0x10,
- PT_KS_DESC = 0x20
-};
-
-
-enum file_api_t {
- FOPS_OPEN = 0,
- FOPS_CLOSE = 1,
- FOPS_READ_BEGIN = 2,
- FOPS_READ_END = 3,
- FOPS_READ = FOPS_READ_BEGIN,
- FOPS_WRITE_BEGIN = 4,
- FOPS_WRITE_END = 5,
- FOPS_WRITE = FOPS_WRITE_BEGIN,
- FOPS_DIRECTORY = 6,
- FOPS_PERMS = 7,
- FOPS_OTHER = 8,
- FOPS_SEND = 9,
- FOPS_RECV = 10,
- FOPS_OPTION = 11,
- FOPS_MANAGE = 12,
- FOPS_LOCK_START = 14, /* 13 */
- FOPS_LOCK_END = 15,
- FOPS_LOCK_RELEASE = 16
-};
-
-
-struct pt_regs;
-
-
-void ksf_msg_entry(struct pt_regs *regs, unsigned long func_addr,
- enum probe_t type, const char *fmt);
-void ksf_msg_exit(struct pt_regs *regs, unsigned long func_addr,
- unsigned long ret_addr, enum probe_t type, char ret_type);
-
-void ksf_msg_file_entry(int fd, enum file_api_t api, const char *path);
-void ksf_msg_file_entry_open(int fd, enum file_api_t api, const char *path,
- const char __user *ofile);
-void ksf_msg_file_entry_lock(int fd, enum file_api_t api, const char *path,
- int type, int whence, s64 start, s64 len);
-void ksf_msg_file_exit(struct pt_regs *regs, char ret_type);
-
-void ksf_switch_entry(struct pt_regs *regs);
-void ksf_switch_exit(struct pt_regs *regs);
-
-
-#endif /* _KSF_MSG_H */
+++ /dev/null
-/**
- * @file ks_features/syscall_list.h
- * @author Vyacheslav Cherkashin: SWAP ks_features implement
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Syscalls list.
- */
-
-
-#ifndef _SYSCALL_LIST_H
-#define _SYSCALL_LIST_H
-
-#define SYSCALL_LIST \
- X(sys_accept4, dpdd), \
- X(sys_accept, dpd), \
- X(sys_access, sd), \
- X(sys_acct, s), \
- X(sys_bind, dpd), \
- X(sys_chdir, s), \
- X(sys_chmod, sd), \
- X(sys_chown16, sdd), \
- X(sys_chown, sdd), \
- X(sys_chroot, s), \
- X(sys_clone, ddddd), \
- X(sys_connect, dpd), \
- X(sys_creat, sd), \
- X(sys_dup3, ddd), \
- X(sys_epoll_create1, d), \
- X(sys_epoll_ctl, dddp), \
- X(sys_epoll_pwait, dpddpx), \
- X(sys_epoll_wait, dpdd), \
- X(sys_eventfd2, dd), \
- X(sys_eventfd, d), \
- X(sys_execve, spp), \
- X(sys_exit, d), \
- X(sys_exit_group, d), \
- X(sys_faccessat, dsd), \
- X(sys_fadvise64_64, dxxd), \
- X(sys_fallocate, ddxx), \
- X(sys_fanotify_init, dd), \
- X(sys_fanotify_mark, ddxds), \
- X(sys_fchmodat, dsd), \
- X(sys_fchownat, dsddd), \
- X(sys_fgetxattr, dspx), \
- X(sys_flistxattr, dpx), \
- X(sys_fork, /* empty */), \
- X(sys_fremovexattr, ds), \
- X(sys_fstat64, xp), \
- X(sys_ftruncate64, dx), \
- X(sys_futimesat, dsp), \
- X(sys_getcwd, px), \
- X(sys_getpeername, dpd), \
- X(sys_getsockname, dpd), \
- X(sys_getsockopt, dddpd), \
- X(sys_getxattr, sspx), \
- X(sys_inotify_add_watch, dsd), \
- X(sys_inotify_init, /* empty */), \
- X(sys_inotify_init1, d), \
- X(sys_inotify_rm_watch, dd), \
- X(sys_ipc, ddxxpx), \
- X(sys_kill, dd), \
- X(sys_linkat, dsdsd), \
- X(sys_link, ss), \
- X(sys_listen, dd), \
- X(sys_listxattr, spx), \
- X(sys_lstat64, sp), \
-/* TODO: X(sys_lstat, sp), */ \
- X(sys_mkdirat, dsd), \
- X(sys_mkdir, sd), \
- X(sys_mknodat, dsdd), \
- X(sys_mknod, sdd), \
- X(sys_mmap_pgoff, xxxxxx), \
- X(sys_mount, pppxp), \
- X(sys_msgctl, ddp), \
- X(sys_msgget, dd), \
- X(sys_msgrcv, dpxxd), \
- X(sys_msgsnd, dpxd), \
- X(sys_name_to_handle_at, dspdd), \
-/* TODO: X(sys_newfstatat, dspd), */ \
- X(sys_old_mmap, p), \
- X(sys_openat, dsdd), \
- X(sys_open_by_handle_at, dpd), \
- X(sys_open, sdd), \
- X(sys_pause, /* empty */), \
- X(sys_pipe2, dd), \
- X(sys_ppoll, pdpp), \
- X(sys_pread64, dpxx), \
- X(sys_preadv, xpxxx), \
- X(sys_pselect6, dxxxpp), \
- X(sys_pwrite64, dsxx), \
- X(sys_pwritev, xpxxx), \
- X(sys_readlinkat, dspd), \
- X(sys_readlink, spd), \
- X(sys_recv, dpxd), \
- X(sys_recvfrom, dpxdpd), \
- X(sys_recvmmsg, dpddp), \
- X(sys_recvmsg, dpd), \
- X(sys_removexattr, ss), \
- X(sys_renameat, dsds), \
- X(sys_rename, ss), \
- X(sys_rmdir, s), \
- X(sys_rt_sigaction, dpp), \
- X(sys_rt_sigprocmask, dppx), \
- X(sys_rt_sigsuspend, px), \
- X(sys_rt_sigtimedwait, pppx), \
- X(sys_rt_tgsigqueueinfo, dddp), \
- X(sys_semctl, dddx), \
- X(sys_semget, ddd), \
- X(sys_semop, dpd), \
- X(sys_semtimedop, dpdp), \
- X(sys_send, dpxd), \
- X(sys_sendfile64, ddlxx), \
- X(sys_sendfile, ddxx), \
- X(sys_sendmmsg, dpdd), \
- X(sys_sendmsg, dpd), \
- X(sys_sendto, dpxdpd), \
- X(sys_setns, dd), \
- X(sys_setsockopt, dddpd), \
- X(sys_setxattr, sspxd), \
- X(sys_shmat, dpd), \
- X(sys_shmctl, ddp), \
- X(sys_shmdt, p), \
- X(sys_shmget, dxd), \
- X(sys_shutdown, dd), \
- X(sys_sigaction, dpp), \
-/* TODO: X(sys_sigaltstack, pp), */ \
-/* TODO: X(sys_signal, dp), */ \
- X(sys_signalfd4, dpxd), \
- X(sys_signalfd, dpx), \
- X(sys_sigpending, p), \
- X(sys_sigprocmask, dpp), \
-/* TODO: X(sys_sigsuspend, ddp), */ \
-/* TODO: X(sys_sigsuspend, p), */ \
- X(sys_socketcall, dx), \
- X(sys_socket, ddd), \
- X(sys_socketpair, dddd), \
- X(sys_splice, dxdxxd), \
- X(sys_stat64, sp), \
- X(sys_statfs64, sxp), \
- X(sys_statfs, sp), \
-/* TODO: X(sys_stat, sp), */ \
- X(sys_swapoff, s), \
- X(sys_swapon, sd), \
- X(sys_symlinkat, sds), \
- X(sys_symlink, ss), \
- X(sys_syncfs, d), \
- X(sys_tee, ddxd), \
- X(sys_tgkill, ddd), \
- X(sys_timerfd_create, dd), \
- X(sys_timerfd_gettime, dp), \
- X(sys_timerfd_settime, ddpp), \
- X(sys_truncate64, sx), \
- X(sys_truncate, sx), \
- X(sys_umount, pd), \
- X(sys_unlinkat, dsd), \
- X(sys_unlink, s), \
- X(sys_unshare, x), \
- X(sys_uselib, s), \
- X(sys_utimensat, dspd), \
- X(sys_utime, pp), \
- X(sys_utimes, pp), \
- X(sys_vfork, /* empty */), \
- X(sys_vmsplice, dpxd), \
- X(sys_wait4, dddp), \
- X(sys_waitid, ddpdp)
-/* TODO: X(sys_waitpid, ddd) */
-
-#endif /* _SYSCALL_LIST_H */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_ksyms.o
-swap_ksyms-y := ksyms_module.o
-
-ifeq ($(CONFIG_KALLSYMS),y)
- swap_ksyms-y += ksyms.o
-else
- swap_ksyms-y += no_ksyms.o
-endif
+++ /dev/null
-/**
- * @file ksyms/ksyms.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * SWAP ksyms module.
- */
-
-
-#include "ksyms.h"
-#include "ksyms_init.h"
-#include <linux/kallsyms.h>
-#include <linux/module.h>
-#include <linux/percpu.h>
-
-/**
- * @struct symbol_data
- * @brief Stores symbols data.
- * @var symbol_data::name
- * Pointer to symbol name string.
- * @var symbol_data::len
- * Symbol name length.
- * @var symbol_data::addr
- * Symbol address.
- */
-struct symbol_data {
- const char *name;
- size_t len;
- unsigned long addr;
-};
-
-static int symbol_cb(void *data, const char *sym, struct module *mod,
- unsigned long addr)
-{
- struct symbol_data *sym_data_p = (struct symbol_data *)data;
-
- /* We expect that real symbol name should have at least the same
- * length as symbol name we are looking for. */
- if (strncmp(sym_data_p->name, sym, sym_data_p->len) == 0) {
- sym_data_p->addr = addr;
- /* Return != 0 to stop loop over the symbols */
- return 1;
- }
-
- return 0;
-}
-
-/**
- * @brief Search of symbol address based on substring.
- *
- * @param name Pointer to the substring.
- * @return Symbol address.
- */
-unsigned long swap_ksyms_substr(const char *name)
-{
- struct symbol_data sym_data = {
- .name = name,
- .len = strlen(name),
- .addr = 0
- };
- kallsyms_on_each_symbol(symbol_cb, (void *)&sym_data);
-
- return sym_data.addr;
-}
-EXPORT_SYMBOL_GPL(swap_ksyms_substr);
+++ /dev/null
-/**
- * @file ksyms/ksyms.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @sectoin DESCRIPTION
- *
- * SWAP symbols searching module.
- */
-
-#ifndef __KSYMS_H__
-#define __KSYMS_H__
-
-#include <linux/version.h>
-#include <generated/autoconf.h>
-
-#include <linux/kallsyms.h>
-
-#ifdef CONFIG_KALLSYMS
-
-static inline int swap_get_ksyms(void)
-{
- return 0;
-}
-
-static inline void swap_put_ksyms(void)
-{
-}
-
-static inline unsigned long swap_ksyms(const char *name)
-{
- return kallsyms_lookup_name(name);
-}
-
-#else /* !CONFIG_KALLSYMS */
-
-int swap_get_ksyms(void);
-void swap_put_ksyms(void);
-unsigned long swap_ksyms(const char *name);
-
-#endif /*CONFIG_KALLSYMS*/
-
-unsigned long swap_ksyms_substr(const char *name);
-
-#endif /*__KSYMS_H__*/
+++ /dev/null
-/**
- * @file ksyms/ksyms_init.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section LICENSE
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * SWAP symbols searching module initialization interface.
- */
-
-#ifndef __KSYMS_INIT_H__
-#define __KSYMS_INIT_H__
-
-#ifdef CONFIG_KALLSYMS
-
-static inline int ksyms_init(void)
-{
- return 0;
-}
-
-static inline void ksyms_exit(void)
-{
-}
-
-#else /* CONFIG_KALLSYMS */
-
-int ksyms_init(void);
-void ksyms_exit(void);
-
-#endif /* CONFIG_KALLSYMS */
-
-#endif /* __KSYMS_INIT_H__ */
+++ /dev/null
-/**
- * @file ksyms/ksyms_module.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * SWAP symbols searching module initialization implementation.
- */
-
-#include "ksyms_init.h"
-
-#include <linux/module.h>
-
-/**
- * @brief Init ksyms module.
- *
- * @return 0 on success.
- */
-int __init swap_ksyms_init(void)
-{
- int ret = ksyms_init();
-
- printk(KERN_INFO "SWAP_KSYMS: Module initialized\n");
-
- return ret;
-}
-
-/**
- * @brief Exit ksyms module.
- *
- * @return Void.
- */
-void __exit swap_ksyms_exit(void)
-{
- ksyms_exit();
-
- printk(KERN_INFO "SWAP_KSYMS: Module uninitialized\n");
-}
-
-module_init(swap_ksyms_init);
-module_exit(swap_ksyms_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP ksyms module");
-MODULE_AUTHOR("Vyacheslav Cherkashin <v.cherkashin@samaung.com>");
+++ /dev/null
-/**
- * @file ksyms/no_ksyms.c
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * SWAP symbols searching implementation.
- */
-
-#include "ksyms.h"
-#include "ksyms_init.h"
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/semaphore.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-
-/**
- * @def KSYMS_ERR
- * Error message define.
- */
-#define KSYMS_ERR(format, args...) \
- do { \
- char *f = __FILE__; \
- char *n = strrchr(f, '/'); \
- printk(KERN_INFO "%s:%u \'%s\' ERROR: " format "\n" , \
- (n) ? n+1 : f, __LINE__, __func__, ##args); \
- } while (0)
-
-/**
- * @struct sys_map_item
- * @brief System map list item info.
- * @var sys_map_item::list
- * List pointer.
- * @var sys_map_item::addr
- * Symbol address.
- * @var sys_map_item::name
- * Symbol name.
- */
-struct sys_map_item {
- struct list_head list;
-
- unsigned long addr;
- char *name;
-};
-
-static char *sm_path;
-module_param(sm_path, charp, 0);
-
-/**
- * @var smi_list
- * List of sys_map_item.
- */
-LIST_HEAD(smi_list);
-static struct file *file;
-
-static int cnt_init_sm;
-
-/**
- * @var cnt_init_sm_lock
- * System map items list lock.
- */
-DEFINE_SEMAPHORE(cnt_init_sm_lock);
-
-static int file_open(void)
-{
- struct file *f = filp_open(sm_path, O_RDONLY, 0);
-
- if (IS_ERR(f)) {
- KSYMS_ERR("cannot open file \'%s\'", sm_path);
- return PTR_ERR(f);
- }
-
- file = f;
-
- return 0;
-}
-
-static void file_close(void)
-{
- if (file) {
- int ret = filp_close(file, NULL);
- file = NULL;
-
- if (ret) {
- KSYMS_ERR("while closing file \'%s\' err=%d",
- sm_path, ret);
- }
- }
-}
-
-static int file_check(void)
-{
- int ret = file_open();
- if (ret == 0)
- file_close();
-
- return ret;
-}
-
-static long file_size(struct file *file)
-{
- struct kstat st;
- if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st))
- return -1;
-
- if (!S_ISREG(st.mode))
- return -1;
-
- if (st.size != (long)st.size)
- return -1;
-
- return st.size;
-}
-
-static struct sys_map_item *create_smi(unsigned long addr, const char *name)
-{
- struct sys_map_item *smi = kmalloc(sizeof(*smi), GFP_KERNEL);
-
- if (smi == NULL) {
- KSYMS_ERR("not enough memory");
- return NULL;
- }
-
- smi->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
- if (smi->name == NULL) {
- kfree(smi);
- KSYMS_ERR("not enough memory");
- return NULL;
- }
-
- INIT_LIST_HEAD(&smi->list);
- smi->addr = addr;
- strcpy(smi->name, name);
-
- return smi;
-}
-
-static void free_smi(struct sys_map_item *smi)
-{
- kfree(smi->name);
- kfree(smi);
-}
-
-static void add_smi(struct sys_map_item *smi)
-{
- list_add_tail(&smi->list, &smi_list);
-}
-
-static int is_endline(char c)
-{
- return c == '\n' || c == '\r' || c == '\0';
-}
-
-static int is_symbol_attr(char c)
-{
- return c == 't' || c == 'T';
-}
-
-static struct sys_map_item *get_sys_map_item(char *begin, char *end)
-{
- struct sys_map_item *smi = NULL;
- int n, len = end - begin;
- unsigned long addr;
- char attr, name[128], *line;
-
- line = kmalloc(len + 1, GFP_KERNEL);
- memcpy(line, begin, len);
- line[len] = '\0';
-
- n = sscanf(line, "%lx %c %127s", &addr, &attr, name);
- name[127] = '\0';
-
- if (n != 3) {
- KSYMS_ERR("parsing line: \"%s\"", line);
- attr = '\0';
- }
-
- kfree(line);
-
- if (is_symbol_attr(attr))
- smi = create_smi(addr, name);
-
- return smi;
-}
-
-
-static void parsing(char *buf, int size)
-{
- struct sys_map_item *smi;
- char *start, *end, *c;
-
- start = buf;
- end = buf + size;
-
- for (c = start; c < end; ++c) {
- if (is_endline(*c)) {
- smi = get_sys_map_item(start, c);
- if (smi)
- add_smi(smi);
-
- for (start = c; c < end; ++c) {
- if (!is_endline(*c)) {
- start = c;
- break;
- }
- }
- }
- }
-}
-
-static int create_sys_map(void)
-{
- char *data;
- long size;
- int ret = file_open();
-
- if (ret)
- return ret;
-
- size = file_size(file);
- if (size < 0) {
- KSYMS_ERR("cannot get file size");
- ret = size;
- goto close;
- }
-
- data = vmalloc(size);
- if (data == NULL) {
- KSYMS_ERR("not enough memory");
- ret = -1;
- goto close;
- }
-
- if (kernel_read(file, 0, data, size) != size) {
- KSYMS_ERR("reading file %s", sm_path);
- ret = -1;
- goto free;
- }
-
- parsing(data, size);
-
-free:
- vfree(data);
-
-close:
- file_close();
-
- return 0;
-}
-
-static void free_sys_map(void)
-{
- struct sys_map_item *smi, *n;
- list_for_each_entry_safe(smi, n, &smi_list, list) {
- list_del(&smi->list);
- free_smi(smi);
- }
-}
-
-/**
- * @brief Generates symbols list.
- *
- * @return 0 on success.
- */
-int swap_get_ksyms(void)
-{
- int ret = 0;
-
- down(&cnt_init_sm_lock);
- if (cnt_init_sm == 0)
- ret = create_sys_map();
-
- ++cnt_init_sm;
- up(&cnt_init_sm_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(swap_get_ksyms);
-
-/**
- * @brief Frees symbols list.
- *
- * @return Void.
- */
-void swap_put_ksyms(void)
-{
- down(&cnt_init_sm_lock);
- --cnt_init_sm;
- if (cnt_init_sm == 0)
- free_sys_map();
-
- if (cnt_init_sm < 0) {
- KSYMS_ERR("cnt_init_sm=%d", cnt_init_sm);
- cnt_init_sm = 0;
- }
-
- up(&cnt_init_sm_lock);
-}
-EXPORT_SYMBOL_GPL(swap_put_ksyms);
-
-/**
- * @brief Searches for symbol by its exact name.
- *
- * @param name Pointer the name string.
- * @return Symbol's address.
- */
-unsigned long swap_ksyms(const char *name)
-{
- struct sys_map_item *smi;
-
- list_for_each_entry(smi, &smi_list, list) {
- if (strcmp(name, smi->name) == 0)
- return smi->addr;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(swap_ksyms);
-
-/**
- * @brief Searches for symbol by substring of its name.
- *
- * @param name Pointer to the name substring.
- * @return Symbol's address.
- */
-unsigned long swap_ksyms_substr(const char *name)
-{
- struct sys_map_item *smi;
- size_t len = strlen(name);
-
- list_for_each_entry(smi, &smi_list, list) {
- if (strncmp(name, smi->name, len) == 0)
- return smi->addr;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(swap_ksyms_substr);
-
-/**
- * @brief SWAP ksyms module initialization.
- *
- * @return 0 on success, negative error code on error.
- */
-int ksyms_init(void)
-{
- int ret = 0;
-
- if (sm_path == NULL) {
- KSYMS_ERR("sm_path=NULL");
- return -EINVAL;
- }
-
- ret = file_check();
- if (ret)
- return -EINVAL;
-
- /* TODO: calling func 'swap_get_ksyms' in
- * module used func 'swap_ksyms' */
- swap_get_ksyms();
-
- return 0;
-}
-
-/**
- * @brief SWAP ksyms module deinitialization.
- *
- * @return Void.
- */
-void ksyms_exit(void)
-{
- down(&cnt_init_sm_lock);
-
- if (cnt_init_sm > 0)
- free_sys_map();
-
- up(&cnt_init_sm_lock);
-}
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_master.o
-swap_master-y := master_module.o \
- swap_debugfs.o \
- swap_initializer.o
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include "swap_debugfs.h"
-#include "swap_initializer.h"
-
-
-static int __init master_init(void)
-{
- return swap_debugfs_init();
-}
-
-static void __exit master_exit(void)
-{
- swap_debugfs_uninit();
-}
-
-module_init(master_init);
-module_exit(master_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include "swap_initializer.h"
-
-
-static int set_enable(int enable)
-{
- int ret = 0, change, enable_current;
-
- enable_current = swap_init_stat_get();
-
- change = ((!!enable_current) << 1) | (!!enable);
- switch (change) {
- case 0b01: /* init */
- ret = swap_init_init();
- break;
- case 0b10: /* uninit */
- ret = swap_init_uninit();
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- swap_init_stat_put();
-
- return ret;
-}
-
-static ssize_t read_enable(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- char buf[3];
- int enable;
-
- enable = swap_init_stat_get();
- swap_init_stat_put();
-
- if (enable)
- buf[0] = '1';
- else
- buf[0] = '0';
- buf[1] = '\n';
- buf[2] = '\0';
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
-}
-
-static int do_write_enable(const char *buf, size_t size)
-{
- if (size < 1)
- return -EINVAL;
-
- switch (buf[0]) {
- case '1':
- return set_enable(1);
- case '0':
- return set_enable(0);
- }
-
- return -EINVAL;
-}
-
-static ssize_t write_enable(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- int ret;
- char buf[32];
- size_t buf_size;
-
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
-
- ret = do_write_enable(buf, buf_size);
-
- return ret ? ret : count;
-}
-
-static const struct file_operations fops_enable = {
- .owner = THIS_MODULE,
- .read = read_enable,
- .write = write_enable,
- .llseek = default_llseek,
-};
-
-
-static struct dentry *swap_dir;
-
-/**
- * @brief Get debugfs dir.
- *
- * @return Pointer to dentry stuct.
- */
-struct dentry *swap_debugfs_getdir(void)
-{
- return swap_dir;
-}
-EXPORT_SYMBOL_GPL(swap_debugfs_getdir);
-
-static int debugfs_dir_init(void)
-{
- swap_dir = debugfs_create_dir("swap", NULL);
- if (swap_dir == NULL)
- return -ENOMEM;
-
- return 0;
-}
-
-static void debugfs_dir_exit(void)
-{
- struct dentry *dir = swap_dir;
-
- swap_dir = NULL;
- debugfs_remove_recursive(dir);
-}
-
-/**
- * @brief Initializes SWAP debugfs.
- *
- * @return 0 on success, negative error code on error.
- */
-int swap_debugfs_init(void)
-{
- int ret;
- struct dentry *dentry;
-
- ret = debugfs_dir_init();
- if (ret)
- return ret;
-
- dentry = debugfs_create_file("enable", 0600, swap_dir, NULL,
- &fops_enable);
- if (dentry == NULL) {
- debugfs_dir_exit();
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/**
- * @brief Deinitializes SWAP debugfs and recursively removes all its files.
- *
- * @return Void.
- */
-void swap_debugfs_uninit(void)
-{
- debugfs_dir_exit();
-}
+++ /dev/null
-/**
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * SWAP debugfs interface definition.
- */
-
-#ifndef _SWAP_DEBUGFS_H
-#define _SWAP_DEBUGFS_H
-
-
-struct dentry;
-
-struct dentry *swap_debugfs_getdir(void);
-
-int swap_debugfs_init(void);
-void swap_debugfs_uninit(void);
-
-
-#endif /* _SWAP_DEBUGFS_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include "swap_initializer.h"
-
-
-enum init_level {
- IL_CORE,
- IL_FS
-};
-
-static swap_init_t sis_get_fn_init(struct swap_init_struct *init,
- enum init_level level)
-{
- switch (level) {
- case IL_CORE:
- return init->core_init;
- case IL_FS:
- return init->fs_init;
- default:
- return NULL;
- }
-}
-
-static swap_uninit_t sis_get_fn_uninit(struct swap_init_struct *init,
- enum init_level level)
-{
- switch (level) {
- case IL_CORE:
- return init->core_uninit;
- case IL_FS:
- return init->fs_uninit;
- }
-
- return NULL;
-}
-
-static void sis_set_flag(struct swap_init_struct *init,
- enum init_level level, bool val)
-{
- switch (level) {
- case IL_CORE:
- init->core_flag = val;
- break;
- case IL_FS:
- init->fs_flag = val;
- break;
- }
-}
-
-static bool sis_get_flag(struct swap_init_struct *init, enum init_level level)
-{
- switch (level) {
- case IL_CORE:
- return init->core_flag;
- case IL_FS:
- return init->fs_flag;
- }
-
- return false;
-}
-
-static int sis_once(struct swap_init_struct *init)
-{
- swap_init_t once;
-
- once = init->once;
- if (!init->once_flag && once) {
- int ret;
-
- ret = once();
- if (ret)
- return ret;
-
- init->once_flag = true;
- }
-
- return 0;
-}
-
-static int sis_init_level(struct swap_init_struct *init, enum init_level level)
-{
- int ret;
- swap_init_t fn;
-
- if (sis_get_flag(init, level))
- return -EPERM;
-
- fn = sis_get_fn_init(init, level);
- if (fn) {
- ret = fn();
- if (ret)
- return ret;
- }
-
- sis_set_flag(init, level, true);
- return 0;
-}
-
-static void sis_uninit_level(struct swap_init_struct *init,
- enum init_level level)
-{
- if (sis_get_flag(init, level)) {
- swap_uninit_t fn = sis_get_fn_uninit(init, level);
- if (fn)
- fn();
- sis_set_flag(init, level, false);
- }
-}
-
-static int sis_init(struct swap_init_struct *init)
-{
- int ret;
-
- ret = sis_once(init);
- if (ret)
- return ret;
-
- ret = sis_init_level(init, IL_CORE);
- if (ret)
- return ret;
-
- ret = sis_init_level(init, IL_FS);
- if (ret)
- sis_uninit_level(init, IL_CORE);
-
- return ret;
-}
-
-static void sis_uninit(struct swap_init_struct *init)
-{
- sis_uninit_level(init, IL_FS);
- sis_uninit_level(init, IL_CORE);
-}
-
-static LIST_HEAD(init_list);
-static DEFINE_MUTEX(inst_mutex);
-static unsigned init_flag;
-
-static int do_once(void)
-{
- int ret;
- struct swap_init_struct *init;
-
- list_for_each_entry(init, &init_list, list) {
- ret = sis_once(init);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static void do_uninit_level(enum init_level level)
-{
- struct swap_init_struct *init;
-
- list_for_each_entry_reverse(init, &init_list, list)
- sis_uninit_level(init, level);
-}
-
-static int do_init_level(enum init_level level)
-{
- int ret;
- struct swap_init_struct *init;
-
- list_for_each_entry(init, &init_list, list) {
- ret = sis_init_level(init, level);
- if (ret) {
- do_uninit_level(level);
- return ret;
- }
- }
-
- return 0;
-}
-
-static int do_init(void)
-{
- int ret;
-
- ret = do_once();
- if (ret)
- return ret;
-
- ret = do_init_level(IL_CORE);
- if (ret)
- return ret;
-
- ret = do_init_level(IL_FS);
- if (ret)
- do_uninit_level(IL_CORE);
-
- init_flag = 1;
-
- return 0;
-}
-
-static void do_uninit(void)
-{
- do_uninit_level(IL_FS);
- do_uninit_level(IL_CORE);
-
- init_flag = 0;
-}
-
-
-static atomic_t init_use = ATOMIC_INIT(0);
-
-enum init_stat_t {
- IS_OFF,
- IS_SWITCHING,
- IS_ON,
-};
-
-static enum init_stat_t init_stat;
-static DEFINE_SPINLOCK(init_stat_lock);
-
-
-static bool swap_init_try_get(void)
-{
- spin_lock(&init_stat_lock);
- if (init_stat != IS_ON) {
- spin_unlock(&init_stat_lock);
- return false;
- }
- spin_unlock(&init_stat_lock);
-
- atomic_inc(&init_use);
-
- return true;
-}
-
-static void swap_init_put(void)
-{
- atomic_dec(&init_use);
-}
-
-int swap_init_simple_open(struct inode *inode, struct file *file)
-{
- if (swap_init_try_get() == false)
- return -EBUSY;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(swap_init_simple_open);
-
-int swap_init_simple_release(struct inode *inode, struct file *file)
-{
- swap_init_put();
- return 0;
-}
-EXPORT_SYMBOL_GPL(swap_init_simple_release);
-
-int swap_init_init(void)
-{
- int ret;
-
- spin_lock(&init_stat_lock);
- init_stat = IS_SWITCHING;
- spin_unlock(&init_stat_lock);
-
- ret = do_init();
-
- spin_lock(&init_stat_lock);
- init_stat = ret ? IS_OFF : IS_ON;
- spin_unlock(&init_stat_lock);
-
- return ret;
-}
-
-int swap_init_uninit(void)
-{
- spin_lock(&init_stat_lock);
- init_stat = IS_SWITCHING;
- if (atomic_read(&init_use)) {
- init_stat = IS_ON;
- spin_unlock(&init_stat_lock);
- return -EBUSY;
- }
- spin_unlock(&init_stat_lock);
-
- do_uninit();
-
- spin_lock(&init_stat_lock);
- init_stat = IS_OFF;
- spin_unlock(&init_stat_lock);
-
- return 0;
-}
-
-
-int swap_init_stat_get(void)
-{
- mutex_lock(&inst_mutex);
-
- return init_flag;
-}
-
-void swap_init_stat_put(void)
-{
- mutex_unlock(&inst_mutex);
-}
-
-int swap_init_register(struct swap_init_struct *init)
-{
- int ret = 0;
-
- mutex_lock(&inst_mutex);
- if (init_flag)
- ret = sis_init(init);
-
- if (ret == 0)
- list_add_tail(&init->list, &init_list);
- mutex_unlock(&inst_mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(swap_init_register);
-
-void swap_init_unregister(struct swap_init_struct *init)
-{
- mutex_lock(&inst_mutex);
- list_del(&init->list);
- sis_uninit(init);
- mutex_unlock(&inst_mutex);
-}
-EXPORT_SYMBOL_GPL(swap_init_unregister);
+++ /dev/null
-/**
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * SWAP event notification interface.
- */
-
-#ifndef _SWAP_INITIALIZER_H
-#define _SWAP_INITIALIZER_H
-
-
-#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/module.h>
-
-
-struct file;
-struct inode;
-
-
-typedef int (*swap_init_t)(void);
-typedef void (*swap_uninit_t)(void);
-
-
-struct swap_init_struct {
- swap_init_t once; /* to call only on the first initialization */
-
- swap_init_t core_init;
- swap_uninit_t core_uninit;
-
- swap_init_t fs_init;
- swap_uninit_t fs_uninit;
-
- /* private fields */
- struct list_head list;
- unsigned once_flag:1;
- unsigned core_flag:1;
- unsigned fs_flag:1;
-};
-
-
-int swap_init_simple_open(struct inode *inode, struct file *file);
-int swap_init_simple_release(struct inode *inode, struct file *file);
-
-int swap_init_init(void);
-int swap_init_uninit(void);
-
-int swap_init_stat_get(void);
-void swap_init_stat_put(void);
-
-int swap_init_register(struct swap_init_struct *init);
-void swap_init_unregister(struct swap_init_struct *init);
-
-
-#define SWAP_LIGHT_INIT_MODULE(_once, _init, _uninit, _fs_init, _fs_uninit) \
- static struct swap_init_struct __init_struct = { \
- .once = _once, \
- .core_init = _init, \
- .core_uninit = _uninit, \
- .fs_init = _fs_init, \
- .fs_uninit = _fs_uninit, \
- .list = LIST_HEAD_INIT(__init_struct.list), \
- .once_flag = false, \
- .core_flag = false, \
- .fs_flag = false \
- }; \
- static int __init __init_mod(void) \
- { \
- return swap_init_register(&__init_struct); \
- } \
- static void __exit __exit_mod(void) \
- { \
- swap_init_unregister(&__init_struct); \
- } \
- module_init(__init_mod); \
- module_exit(__exit_mod)
-
-
-#endif /* _SWAP_INITIALIZER_H */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_nsp.o
-swap_nsp-y := \
- nsp_module.o \
- nsp.o \
- nsp_msg.o \
- nsp_tdata.o \
- nsp_debugfs.o
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <writer/swap_msg.h>
-#include <uprobe/swap_uaccess.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/probes/probe_info_new.h>
-#include "nsp.h"
-#include "nsp_msg.h"
-#include "nsp_tdata.h"
-#include "nsp_print.h"
-#include "nsp_debugfs.h"
-
-
-/* ============================================================================
- * = probes =
- * ============================================================================
- */
-
-/* dlopen@plt */
-static int dlopen_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static int dlopen_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_info_new pin_dlopen = MAKE_URPROBE(dlopen_eh, dlopen_rh, 0);
-static struct probe_new p_dlopen = {
- .info = &pin_dlopen
-};
-
-/* dlsym@plt */
-static int dlsym_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static int dlsym_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_info_new pin_dlsym = MAKE_URPROBE(dlsym_eh, dlsym_rh, 0);
-static struct probe_new p_dlsym = {
- .info = &pin_dlsym
-};
-
-/* main */
-static int main_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static int main_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_info_new pin_main = MAKE_URPROBE(main_eh, main_rh, 0);
-
-/* appcore_efl_main */
-static int ac_efl_main_h(struct kprobe *p, struct pt_regs *regs);
-static struct probe_info_new pin_ac_efl_main = MAKE_UPROBE(ac_efl_main_h);
-static struct probe_new p_ac_efl_main = {
- .info = &pin_ac_efl_main
-};
-
-/* appcore_init@plt */
-static int ac_init_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_info_new pin_ac_init = MAKE_URPROBE(NULL, ac_init_rh, 0);
-static struct probe_new p_ac_init = {
- .info = &pin_ac_init
-};
-
-/* elm_run@plt */
-static int elm_run_h(struct kprobe *p, struct pt_regs *regs);
-static struct probe_info_new pin_elm_run = MAKE_UPROBE(elm_run_h);
-static struct probe_new p_elm_run = {
- .info = &pin_elm_run
-};
-
-/* __do_app */
-static int do_app_eh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static int do_app_rh(struct uretprobe_instance *ri, struct pt_regs *regs);
-static struct probe_info_new pin_do_app = MAKE_URPROBE(do_app_eh, do_app_rh, 0);
-static struct probe_new p_do_app = {
- .info = &pin_do_app
-};
-
-
-
-
-
-/* ============================================================================
- * = the variables are initialized by the user =
- * ============================================================================
- */
-static const char *lpad_path;
-static struct dentry *lpad_dentry;
-
-static const char *libappcore_path;
-static struct dentry *libappcore_dentry;
-
-static void uninit_variables(void)
-{
- kfree(lpad_path);
- lpad_path = NULL;
- lpad_dentry = NULL;
-
- kfree(libappcore_path);
- libappcore_path = NULL;
- libappcore_dentry = NULL;
-}
-
-static bool is_init(void)
-{
- return lpad_dentry && libappcore_dentry;
-}
-
-static int do_set_lpad_info(const char *path, unsigned long dlopen,
- unsigned long dlsym)
-{
- struct dentry *dentry;
- const char *new_path;
-
- dentry = dentry_by_path(path);
- if (dentry == NULL) {
- pr_err("dentry not found (path='%s')\n", path);
- return -EINVAL;
- }
-
- new_path = kstrdup(path, GFP_KERNEL);
- if (new_path == NULL) {
- pr_err("out of memory\n");
- return -ENOMEM;
- }
-
- kfree(lpad_path);
-
- lpad_path = new_path;
- lpad_dentry = dentry;
- p_dlopen.offset = dlopen;
- p_dlsym.offset = dlsym;
-
- return 0;
-}
-
-static int do_set_appcore_info(struct appcore_info_data *info)
-{
- struct dentry *dentry;
- const char *new_path;
-
- dentry = dentry_by_path(info->path);
- if (dentry == NULL) {
- pr_err("dentry not found (path='%s')\n", info->path);
- return -EINVAL;
- }
-
- new_path = kstrdup(info->path, GFP_KERNEL);
- if (new_path == NULL) {
- pr_err("out of memory\n");
- return -ENOMEM;
- }
-
- kfree(libappcore_path);
-
- libappcore_path = new_path;
- libappcore_dentry = dentry;
- p_ac_efl_main.offset = info->ac_efl_main;
- p_ac_init.offset = info->ac_init;
- p_elm_run.offset = info->elm_run;
- p_do_app.offset = info->do_app;
-
- return 0;
-}
-
-
-
-
-
-/* ============================================================================
- * = nsp_data =
- * ============================================================================
- */
-struct nsp_data {
- struct list_head list;
-
- const char *app_path;
- struct dentry *app_dentry;
- struct probe_new p_main;
-
- struct pf_group *pfg;
-};
-
-static LIST_HEAD(nsp_data_list);
-
-static struct nsp_data *nsp_data_create(const char *app_path,
- unsigned long main_addr)
-{
- struct dentry *dentry;
- struct nsp_data *data;
-
- dentry = dentry_by_path(app_path);
- if (dentry == NULL)
- return ERR_PTR(-ENOENT);
-
- data = kmalloc(sizeof(*data), GFP_KERNEL);
- if (data == NULL)
- return ERR_PTR(-ENOMEM);
-
- data->app_path = kstrdup(app_path, GFP_KERNEL);
- if (data->app_path == NULL) {
- kfree(data);
- return ERR_PTR(-ENOMEM);
- }
-
- data->app_dentry = dentry;
- data->p_main.info = &pin_main;
- data->p_main.offset = main_addr;
- data->pfg = NULL;
-
- return data;
-}
-
-static void nsp_data_destroy(struct nsp_data *data)
-{
- kfree(data->app_path);
- kfree(data);
-}
-
-static struct nsp_data *nsp_data_find(const struct dentry *dentry)
-{
- struct nsp_data *data;
-
- list_for_each_entry(data, &nsp_data_list, list) {
- if (data->app_dentry == dentry)
- return data;
- }
-
- return NULL;
-}
-
-static struct nsp_data *nsp_data_find_by_path(const char *path)
-{
- struct nsp_data *data;
-
- list_for_each_entry(data, &nsp_data_list, list) {
- if (strcmp(data->app_path, path) == 0)
- return data;
- }
-
- return NULL;
-}
-
-static void nsp_data_add(struct nsp_data *data)
-{
- list_add(&data->list, &nsp_data_list);
-}
-
-static void nsp_data_rm(struct nsp_data *data)
-{
- list_del(&data->list);
-}
-
-static int nsp_data_inst(struct nsp_data *data)
-{
- int ret;
- struct pf_group *pfg;
-
- pfg = get_pf_group_by_dentry(lpad_dentry, (void *)data->app_dentry);
- if (pfg == NULL)
- return -ENOMEM;
-
- ret = pin_register(&p_dlsym, pfg, lpad_dentry);
- if (ret)
- goto put_g;
-
- ret = pin_register(&p_dlopen, pfg, lpad_dentry);
- if (ret)
- goto ur_dlsym;
-
- ret = pin_register(&data->p_main, pfg, data->app_dentry);
- if (ret)
- goto ur_dlopen;
-
- ret = pin_register(&p_ac_efl_main, pfg, libappcore_dentry);
- if (ret)
- goto ur_main;
-
- ret = pin_register(&p_ac_init, pfg, libappcore_dentry);
- if (ret)
- goto ur_ac_efl_main;
-
- ret = pin_register(&p_elm_run, pfg, libappcore_dentry);
- if (ret)
- goto ur_ac_init;
-
- ret = pin_register(&p_do_app, pfg, libappcore_dentry);
- if (ret)
- goto ur_elm_run;
-
- data->pfg = pfg;
-
- return 0;
-
-ur_elm_run:
- pin_unregister(&p_elm_run, pfg, libappcore_dentry);
-ur_ac_init:
- pin_unregister(&p_ac_init, pfg, libappcore_dentry);
-ur_ac_efl_main:
- pin_unregister(&p_ac_efl_main, pfg, libappcore_dentry);
-ur_main:
- pin_unregister(&data->p_main, pfg, data->app_dentry);
-ur_dlopen:
- pin_unregister(&p_dlopen, pfg, lpad_dentry);
-ur_dlsym:
- pin_unregister(&p_dlsym, pfg, lpad_dentry);
-put_g:
- put_pf_group(pfg);
- return ret;
-}
-
-static void nsp_data_uninst(struct nsp_data *data)
-{
- struct pf_group *pfg = data->pfg;
-
- pin_unregister(&p_do_app, pfg, libappcore_dentry);
- pin_unregister(&p_elm_run, pfg, libappcore_dentry);
- pin_unregister(&p_ac_init, pfg, libappcore_dentry);
- pin_unregister(&p_ac_efl_main, pfg, libappcore_dentry);
- pin_unregister(&data->p_main, pfg, data->app_dentry);
- pin_unregister(&p_dlopen, pfg, lpad_dentry);
- pin_unregister(&p_dlsym, pfg, lpad_dentry);
- put_pf_group(pfg);
-
- data->pfg = NULL;
-}
-
-static int __nsp_add(const char *app_path, unsigned long main_addr)
-{
- struct nsp_data *data;
-
- if (nsp_data_find_by_path(app_path))
- return -EEXIST;
-
- data = nsp_data_create(app_path, main_addr);
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- nsp_data_add(data);
-
- return 0;
-}
-
-static int __nsp_rm(const char *path)
-{
- struct dentry *dentry;
- struct nsp_data *data;
-
- dentry = dentry_by_path(path);
- if (dentry == NULL)
- return -ENOENT;
-
- data = nsp_data_find(dentry);
- if (data == NULL)
- return -ESRCH;
-
- nsp_data_rm(data);
- nsp_data_destroy(data);
-
- return 0;
-}
-
-static int __nsp_rm_all(void)
-{
- struct nsp_data *data, *n;
-
- list_for_each_entry_safe(data, n, &nsp_data_list, list) {
- nsp_data_rm(data);
- nsp_data_destroy(data);
- }
-
- return 0;
-}
-
-static void __nsp_disabel(void)
-{
- struct nsp_data *data;
-
- list_for_each_entry(data, &nsp_data_list, list) {
- if (data->pfg)
- nsp_data_uninst(data);
- }
-}
-
-static int __nsp_enable(void)
-{
- int ret;
- struct nsp_data *data;
-
- list_for_each_entry(data, &nsp_data_list, list) {
- ret = nsp_data_inst(data);
- if (ret)
- goto fail;
- }
-
- return 0;
-
-fail:
- __nsp_disabel();
- return ret;
-}
-
-
-
-
-
-
-
-/* ============================================================================
- * = set parameters =
- * ============================================================================
- */
-#define F_ARG1(m, t, a) m(t, a)
-#define F_ARG2(m, t, a, ...) m(t, a), F_ARG1(m, __VA_ARGS__)
-#define F_ARG3(m, t, a, ...) m(t, a), F_ARG2(m, __VA_ARGS__)
-#define F_ARG(n, m, ...) F_ARG##n(m, __VA_ARGS__)
-
-#define M_TYPE_AND_ARG(t, a) t a
-#define M_ARG(t, a) a
-
-#define DECLARE_SAFE_FUNC(n, func_name, do_func, ...) \
-int func_name(F_ARG(n, M_TYPE_AND_ARG, __VA_ARGS__)) \
-{ \
- int ret; \
- mutex_lock(&stat_mutex); \
- if (stat == NS_ON) { \
- ret = -EBUSY; \
- goto unlock; \
- } \
- ret = do_func(F_ARG(n, M_ARG, __VA_ARGS__)); \
-unlock: \
- mutex_unlock(&stat_mutex); \
- return ret; \
-}
-
-#define DECLARE_SAFE_FUNC0(name, _do) DECLARE_SAFE_FUNC(1, name, _do, void, /* */);
-#define DECLARE_SAFE_FUNC1(name, _do, ...) DECLARE_SAFE_FUNC(1, name, _do, __VA_ARGS__);
-#define DECLARE_SAFE_FUNC2(name, _do, ...) DECLARE_SAFE_FUNC(2, name, _do, __VA_ARGS__);
-#define DECLARE_SAFE_FUNC3(name, _do, ...) DECLARE_SAFE_FUNC(3, name, _do, __VA_ARGS__);
-
-
-static DEFINE_MUTEX(stat_mutex);
-static enum nsp_stat stat = NS_OFF;
-
-DECLARE_SAFE_FUNC2(nsp_add, __nsp_add, const char *, app_path,
- unsigned long, main_addr);
-DECLARE_SAFE_FUNC1(nsp_rm, __nsp_rm, const char *, app_path);
-DECLARE_SAFE_FUNC0(nsp_rm_all, __nsp_rm_all);
-DECLARE_SAFE_FUNC3(nsp_set_lpad_info, do_set_lpad_info,
- const char *, path, unsigned long, dlopen,
- unsigned long, dlsym);
-DECLARE_SAFE_FUNC1(nsp_set_appcore_info, do_set_appcore_info,
- struct appcore_info_data *, info);
-
-
-
-
-
-/* ============================================================================
- * = set stat =
- * ============================================================================
- */
-static int set_stat_off(void)
-{
- if (stat == NS_OFF)
- return -EINVAL;
-
- __nsp_disabel();
- tdata_disable();
-
- stat = NS_OFF;
-
- return 0;
-}
-
-static int set_stat_on(void)
-{
- int ret;
-
- if (is_init() == false)
- return -EPERM;
-
- if (stat == NS_ON)
- return -EINVAL;
-
- ret = tdata_enable();
- if (ret)
- return ret;
-
- __nsp_enable();
-
- stat = NS_ON;
-
- return 0;
-}
-
-int nsp_set_stat(enum nsp_stat st)
-{
- int ret = -EINVAL;
-
- mutex_lock(&stat_mutex);
- switch (st) {
- case NS_OFF:
- ret = set_stat_off();
- break;
- case NS_ON:
- ret = set_stat_on();
- break;
- }
- mutex_unlock(&stat_mutex);
-
- return ret;
-}
-
-enum nsp_stat nsp_get_stat(void)
-{
- return stat;
-}
-
-
-
-
-
-/* ============================================================================
- * = handlers =
- * ============================================================================
- */
-static int dlopen_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- const char __user *user_s = (const char __user *)swap_get_uarg(regs, 0);
- const char *path;
- struct nsp_data *nsp_data;
-
- path = strdup_from_user(user_s, GFP_ATOMIC);
- if (path == NULL)
- return 0;
-
- nsp_data = nsp_data_find_by_path(path);
- if (nsp_data) {
- struct task_struct *task = current;
- struct tdata *tdata;
-
- tdata = tdata_get(task);
- if (tdata) {
- nsp_print("ERROR: dlopen already cal for '%s'\n", path);
- tdata_put(tdata);
- goto free_path;
- }
-
- tdata = tdata_create(task);
- if (tdata) {
- tdata->stat = NPS_OPEN_E;
- tdata->time = swap_msg_current_time();
- tdata->nsp_data = nsp_data;
- tdata_put(tdata);
- } else {
- nsp_print("ERROR: out of memory\n");
- }
- }
-
-free_path:
- kfree(path);
- return 0;
-}
-
-static int dlopen_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct tdata *tdata;
-
- tdata = tdata_get(current);
- if (tdata) {
- void *handle;
-
- handle = (void *)regs_return_value(regs);
- if ((tdata->stat == NPS_OPEN_E) && handle) {
- tdata->stat = NPS_OPEN_R;
- tdata->handle = handle;
- tdata_put(tdata);
- } else {
- tdata_destroy(tdata);
- }
- }
-
- return 0;
-}
-
-static int dlsym_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct tdata *tdata;
-
- tdata = tdata_get(current);
- if (tdata) {
- const char __user *str = (char __user *)swap_get_uarg(regs, 1);
- const char *name;
- void *handle;
-
- handle = (void *)swap_get_uarg(regs, 0);
- if (handle == tdata->handle && tdata->stat == NPS_OPEN_R) {
- name = strdup_from_user(str, GFP_ATOMIC);
- if (name && (strcmp(name, "main") == 0))
- tdata->stat = NPS_SYM_E;
-
- kfree(name);
- }
-
- tdata_put(tdata);
- }
-
- return 0;
-}
-
-static int dlsym_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct tdata *tdata;
-
- tdata = tdata_get(current);
- if (tdata) {
- if (tdata->stat == NPS_SYM_E)
- tdata->stat = NPS_SYM_R;
- tdata_put(tdata);
- }
-
- return 0;
-}
-
-static void stage_begin(enum nsp_proc_stat priv, enum nsp_proc_stat cur)
-{
- struct tdata *tdata;
-
- tdata = tdata_get(current);
- if (tdata) {
- if (tdata->stat == priv) {
- tdata->stat = cur;
- tdata->time = swap_msg_current_time();
- }
-
- tdata_put(tdata);
- }
-}
-
-static void stage_end(enum nsp_proc_stat priv, enum nsp_proc_stat cur,
- enum nsp_msg_stage st)
-{
- struct tdata *tdata;
- u64 time_start;
- u64 time_end;
-
- tdata = tdata_get(current);
- if (tdata) {
- if (tdata->stat != priv) {
- tdata_put(tdata);
- return;
- }
-
- tdata->stat = cur;
- time_start = tdata->time;
- tdata_put(tdata);
-
- time_end = swap_msg_current_time();
- nsp_msg(st, time_start, time_end);
- }
-}
-
-static int main_h(struct kprobe *p, struct pt_regs *regs)
-{
- struct tdata *tdata;
- u64 time_start;
- u64 time_end;
-
- tdata = tdata_get(current);
- if (tdata) {
- if (tdata->stat != NPS_SYM_R) {
- tdata_put(tdata);
- return 0;
- }
-
- tdata->stat = NPS_MAIN_E;
- time_start = tdata->time;
- time_end = swap_msg_current_time();
- tdata->time = time_end;
-
- tdata_put(tdata);
-
- nsp_msg(NMS_MAPPING, time_start, time_end);
- }
-
- return 0;
-}
-
-/* FIXME: workaround for simultaneously nsp and main() function profiling */
-#include <retprobe/rp_msg.h>
-#include <us_manager/us_manager.h>
-
-static int main_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct uretprobe *rp = ri->rp;
-
- if (rp) {
- main_h(&rp->up.kp, regs);
-
- if (get_quiet() == QT_OFF) {
- struct us_ip *ip;
- unsigned long func_addr;
-
- ip = container_of(rp, struct us_ip, retprobe);
- func_addr = (unsigned long)ip->orig_addr;
- rp_msg_entry(regs, func_addr, "p");
- }
- }
-
- return 0;
-}
-
-static int main_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct uretprobe *rp = ri->rp;
-
- if (rp && get_quiet() == QT_OFF) {
- struct us_ip *ip;
- char ret_type;
- unsigned long func_addr;
- unsigned long ret_addr;
-
- ip = container_of(rp, struct us_ip, retprobe);
- func_addr = (unsigned long)ip->orig_addr;
- ret_addr = (unsigned long)ri->ret_addr;
- ret_type = ip->info->rp_i.ret_type;
- rp_msg_exit(regs, func_addr, 'n', ret_addr);
- }
-
- return 0;
-}
-
-static int ac_efl_main_h(struct kprobe *p, struct pt_regs *regs)
-{
- stage_end(NPS_MAIN_E, NPS_AC_EFL_MAIN_E, NMS_MAIN);
- return 0;
-}
-
-static int ac_init_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- stage_begin(NPS_AC_EFL_MAIN_E, NPS_AC_INIT_R);
- return 0;
-}
-
-static int elm_run_h(struct kprobe *p, struct pt_regs *regs)
-{
- stage_end(NPS_AC_INIT_R, NPS_ELM_RUN_E, NMS_CREATE);
- return 0;
-}
-
-static int do_app_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- int event = swap_get_uarg(regs, 0);
- enum { AE_RESET = 5 }; /* FIXME: hardcode */
-
- if (event == AE_RESET)
- stage_begin(NPS_ELM_RUN_E, NPS_DO_APP_E);
-
- return 0;
-}
-
-static int do_app_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- stage_end(NPS_DO_APP_E, NPS_DO_APP_R, NMS_RESET);
- return 0;
-}
-
-
-
-
-
-int nsp_init(void)
-{
- return 0;
-}
-
-void nsp_exit(void)
-{
- if (stat == NS_ON)
- set_stat_off();
-
- uninit_variables();
-}
+++ /dev/null
-#ifndef _NSP_H
-#define _NSP_H
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-enum offset_t {
- OS_CREATE,
- OS_RESET
-};
-
-enum nsp_stat {
- NS_OFF,
- NS_ON
-};
-
-struct appcore_info_data {
- const char *path;
- unsigned long ac_efl_main;
- unsigned long do_app;
- unsigned long ac_init;
- unsigned long elm_run;
-};
-
-int nsp_init(void);
-void nsp_exit(void);
-
-int nsp_set_lpad_info(const char *path, unsigned long dlopen,
- unsigned long dlsym);
-int nsp_set_appcore_info(struct appcore_info_data *info);
-
-int nsp_set_stat(enum nsp_stat st);
-enum nsp_stat nsp_get_stat(void);
-
-int nsp_add(const char *app_path, unsigned long main_addr);
-int nsp_rm(const char *app_path);
-int nsp_rm_all(void);
-
-
-#endif /* _NSP_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/limits.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <master/swap_debugfs.h>
-#include "nsp.h"
-
-
-/* remove end-line symbols */
-static void rm_endline_symbols(char *buf, size_t len)
-{
- char *p, *buf_end;
-
- buf_end = buf + len;
- for (p = buf; p != buf_end; ++p)
- if (*p == '\n' || *p == '\r')
- *p = '\0';
-}
-
-/*
- * format:
- * main:app_path
- *
- * sample:
- * 0x00000d60:/bin/app_sample
- */
-static int do_add(const char *buf, size_t len)
-{
- int n, ret;
- char *app_path;
- unsigned long main_addr;
- const char fmt[] = "%%lx:/%%%ds";
- char fmt_buf[64];
-
- n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
- if (n <= 0)
- return -EINVAL;
-
- app_path = kmalloc(PATH_MAX, GFP_KERNEL);
- if (app_path == NULL)
- return -ENOMEM;
-
- n = sscanf(buf, fmt_buf, &main_addr, app_path + 1);
- if (n != 2) {
- ret = -EINVAL;
- goto free_app_path;
- }
- app_path[0] = '/';
-
- ret = nsp_add(app_path, main_addr);
-
-free_app_path:
- kfree(app_path);
- return ret;
-}
-
-/*
- * format:
- * path
- *
- * sample:
- * /tmp/sample
- */
-static int do_rm(const char *buf, size_t len)
-{
- return nsp_rm(buf);
-}
-
-static int do_rm_all(const char *buf, size_t len)
-{
- return nsp_rm_all();
-}
-
-/*
- * format:
- * dlopen_addr@plt:dlsym_addr@plt:launchpad_path
- *
- * sample:
- * 0x000234:0x000342:/usr/bin/launchpad-loader
- */
-static int do_set_lpad_info(const char *data, size_t len)
-{
- int n, ret;
- unsigned long dlopen_addr;
- unsigned long dlsym_addr;
- char *lpad_path;
- const char fmt[] = "%%lx:%%lx:/%%%ds";
- char fmt_buf[64];
-
- n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
- if (n <= 0)
- return -EINVAL;
-
- lpad_path = kmalloc(PATH_MAX, GFP_KERNEL);
- if (lpad_path == NULL)
- return -ENOMEM;
-
- n = sscanf(data, fmt_buf, &dlopen_addr, &dlsym_addr, lpad_path + 1);
- if (n != 3) {
- ret = -EINVAL;
- goto free_lpad_path;
- }
- lpad_path[0] = '/';
-
- ret = nsp_set_lpad_info(lpad_path, dlopen_addr, dlsym_addr);
-
-free_lpad_path:
- kfree(lpad_path);
- return ret;
-}
-
-/*
- * format:
- * appcore_efl_main:__do_app:appcore_init@plt:elm_run@plt:libappcore-efl
- *
- * sample:
- * 0x3730:0x2960:0x1810:0x1c70:/usr/lib/libappcore-efl.so.1
- */
-static int do_set_appcore_info(const char *data, size_t len)
-{
- int n, ret;
- struct appcore_info_data info;
- const char fmt[] = "%%lx:%%lx:%%lx:%%lx:/%%%ds";
- char fmt_buf[64];
- char *path;
-
- n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
- if (n <= 0)
- return -EINVAL;
-
- path = kmalloc(PATH_MAX, GFP_KERNEL);
- if (path == NULL)
- return -ENOMEM;
-
- n = sscanf(data, fmt_buf,
- &info.ac_efl_main, &info.do_app,
- &info.ac_init, &info.elm_run, path + 1);
- if (n != 5) {
- ret = -EINVAL;
- goto free_lib_path;
- }
- path[0] = '/';
-
- info.path = path;
- ret = nsp_set_appcore_info(&info);
-
-free_lib_path:
- kfree(path);
- return ret;
-}
-
-/*
- * format:
- * 0 byte - type
- * 1 byte - ' '
- * 2.. bytes - data
- */
-static int do_cmd(const char *data, size_t len)
-{
- char type;
- size_t len_data;
- const char *cmd_data;
-
- if (len) {
- if (data[0] == 'c')
- return do_rm_all(data + 1, len - 1);
- }
- /*
- * 0 byte - type
- * 1 byte - ' '
- */
- if (len < 2 || data[1] != ' ')
- return -EINVAL;
-
- len_data = len - 2;
- cmd_data = data + 2;
- type = data[0];
- switch (type) {
- case 'a':
- return do_add(cmd_data, len_data);
- case 'b':
- return do_set_lpad_info(cmd_data, len_data);
- case 'l':
- return do_set_appcore_info(cmd_data, len_data);
- case 'r':
- return do_rm(cmd_data, len_data);
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-
-
-
-/* ============================================================================
- * === DEBUGFS FOR CMD ===
- * ============================================================================
- */
-static ssize_t write_cmd(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- char *buf;
- ssize_t ret = count;
-
- buf = kmalloc(count + 1, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- if (copy_from_user(buf, user_buf, count)) {
- ret = -EFAULT;
- goto free_buf;
- }
-
- buf[count] = '\0';
- rm_endline_symbols(buf, count);
-
- if (do_cmd(buf, count))
- ret = -EINVAL;
-
-free_buf:
- kfree(buf);
-
- return ret;
-}
-
-static ssize_t read_cmd(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- const char help[] =
- "use:\n"
- "\ta $app_path - add\n"
- "\tr $app_path - remove\n"
- "\tc - remove all\n"
- "\tb dlopen_addr@plt:dlsym_addr@plt:launchpad_path\n"
- "\tl appcore_efl_main:__do_app:appcore_init@plt:elm_run@plt:libappcore-efl_path\n";
- ssize_t ret;
-
- ret = simple_read_from_buffer(user_buf, count, ppos,
- help, sizeof(help));
-
- return ret;
-}
-
-static const struct file_operations fops_cmd = {
- .read = read_cmd,
- .write = write_cmd,
- .llseek = default_llseek
-};
-
-
-
-
-/* ============================================================================
- * === DEBUGFS FOR ENABLE ===
- * ============================================================================
- */
-static ssize_t read_enabled(struct file *file, char /*__user*/ *user_buf,
- size_t count, loff_t *ppos)
-{
- char buf[2];
-
- buf[0] = nsp_get_stat() == NS_OFF ? '0' : '1';
- buf[1] = '\n';
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
-}
-
-static ssize_t write_enabled(struct file *file, const char /*__user*/ *user_buf,
- size_t count, loff_t *ppos)
-{
- int ret = 0;
- char buf[32];
- size_t buf_size;
-
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
-
- buf[buf_size] = '\0';
- switch (buf[0]) {
- case '1':
- ret = nsp_set_stat(NS_ON);
- break;
- case '0':
- ret = nsp_set_stat(NS_OFF);
- break;
- default:
- return -EINVAL;
- }
-
- if (ret)
- return ret;
-
- return count;
-}
-
-static const struct file_operations fops_enabled = {
- .read = read_enabled,
- .write = write_enabled,
- .llseek = default_llseek,
-};
-
-
-
-
-static struct dentry *nsp_dir = NULL;
-
-void nsp_debugfs_exit(void)
-{
- if (nsp_dir)
- debugfs_remove_recursive(nsp_dir);
-
- nsp_dir = NULL;
-}
-
-int nsp_debugfs_init(void)
-{
- struct dentry *dentry;
-
- dentry = swap_debugfs_getdir();
- if (dentry == NULL)
- return -ENOENT;
-
- nsp_dir = debugfs_create_dir("nsp", dentry);
- if (nsp_dir == NULL)
- return -ENOMEM;
-
- dentry = debugfs_create_file("cmd", 0600, nsp_dir, NULL,
- &fops_cmd);
- if (dentry == NULL)
- goto fail;
-
- dentry = debugfs_create_file("enabled", 0600, nsp_dir, NULL,
- &fops_enabled);
- if (dentry == NULL)
- goto fail;
-
- return 0;
-
-fail:
- nsp_debugfs_exit();
- return -ENOMEM;
-}
+++ /dev/null
-#ifndef _NSP_DEBUGFS_H
-#define _NSP_DEBUGFS_H
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-int nsp_debugfs_init(void);
-void nsp_debugfs_exit(void);
-
-
-#endif /* _NSP_DEBUGFS_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <master/swap_initializer.h>
-#include "nsp.h"
-#include "nsp_tdata.h"
-#include "nsp_debugfs.h"
-
-
-SWAP_LIGHT_INIT_MODULE(tdata_once, nsp_init, nsp_exit,
- nsp_debugfs_init, nsp_debugfs_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/sched.h>
-#include <writer/swap_msg.h>
-#include "nsp_msg.h"
-
-
-struct nsp_msg_struct {
- u32 pid;
- u32 stage;
- u64 begin_time;
- u64 end_time;
-} __packed;
-
-
-void nsp_msg(enum nsp_msg_stage stage, u64 begin_time, u64 end_time)
-{
- struct swap_msg *m;
- struct nsp_msg_struct *nsp;
-
- m = swap_msg_get(MSG_NSP);
-
- nsp = (struct nsp_msg_struct *)swap_msg_payload(m);
- nsp->pid = (u32)current->tgid;
- nsp->stage = (u32)stage;
- nsp->begin_time = begin_time;
- nsp->end_time = end_time;
-
- swap_msg_flush(m, sizeof(*nsp));
- swap_msg_put(m);
-}
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#ifndef _NSP_MSG_H
-#define _NSP_MSG_H
-
-
-#include <linux/types.h>
-
-
-enum nsp_msg_stage {
- NMS_MAPPING = 0x00,
- NMS_MAIN = 0x01,
- NMS_CREATE = 0x02,
- NMS_RESET = 0x03,
-};
-
-
-void nsp_msg(enum nsp_msg_stage stage, u64 begin_time, u64 end_time);
-
-
-#endif /* _NSP_MSG_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#ifndef _NSP_PRINT_H
-#define _NSP_PRINT_H
-
-
-#include <linux/printk.h>
-
-
-#define NSP_PREFIX "[NSP] "
-
-#define nsp_print(...) printk(NSP_PREFIX __VA_ARGS__)
-
-
-#endif /* _NSP_PRINT_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <writer/swap_msg.h>
-#include <kprobe/swap_kprobes.h>
-#include <ksyms/ksyms.h>
-#include "nsp_tdata.h"
-#include "nsp_print.h"
-
-
-/* ============================================================================
- * = priv_tdata =
- * ============================================================================
- */
-struct priv_tdata {
- struct list_head list;
- struct task_struct *task;
-
- struct tdata tdata;
-};
-
-
-static LIST_HEAD(task_list);
-static DEFINE_SPINLOCK(task_list_lock);
-
-
-/* called with task_list_lock held */
-static struct priv_tdata *priv_tdata_create(struct task_struct *task)
-{
- struct priv_tdata *p_tdata;
-
- p_tdata = kmalloc(sizeof(*p_tdata), GFP_ATOMIC);
- if (p_tdata) {
- INIT_LIST_HEAD(&p_tdata->list);
- p_tdata->task = task;
-
- /* add to list */
- list_add(&p_tdata->list, &task_list);
- }
-
- return p_tdata;
-}
-
-/* called with task_list_lock held */
-static void priv_tdata_destroy(struct priv_tdata *p_tdata)
-{
- /* delete from list */
- list_del(&p_tdata->list);
-
- kfree(p_tdata);
-}
-
-/* called with task_list_lock held */
-static void __priv_tdata_destroy(struct tdata *tdata)
-{
- struct priv_tdata *p_tdata;
-
- p_tdata = container_of(tdata, struct priv_tdata, tdata);
- priv_tdata_destroy(p_tdata);
-}
-
-/* called with task_list_lock held */
-static void priv_tdata_destroy_all(void)
-{
- struct priv_tdata *p_tdata, *n;
-
- list_for_each_entry_safe(p_tdata, n, &task_list, list)
- priv_tdata_destroy(p_tdata);
-}
-
-
-
-
-
-/* ============================================================================
- * = tdata =
- * ============================================================================
- */
-struct tdata *tdata_create(struct task_struct *task)
-{
- struct priv_tdata *p_tdata;
-
- spin_lock(&task_list_lock);
- p_tdata = priv_tdata_create(task);
- if (p_tdata)
- return &p_tdata->tdata;
- spin_unlock(&task_list_lock);
-
- return NULL;
-
-}
-
-void tdata_destroy(struct tdata *tdata)
-{
- __priv_tdata_destroy(tdata);
- spin_unlock(&task_list_lock);
-}
-
-struct tdata *tdata_find(struct task_struct *task)
-{
- struct priv_tdata *p_tdata;
-
- list_for_each_entry(p_tdata, &task_list, list) {
- if (p_tdata->task == task)
- return &p_tdata->tdata;
- }
-
- return NULL;
-}
-
-struct tdata *tdata_get(struct task_struct *task)
-{
- struct tdata *tdata;
-
- spin_lock(&task_list_lock);
- tdata = tdata_find(task);
- if (tdata)
- return tdata;
- spin_unlock(&task_list_lock);
-
- return NULL;
-}
-
-void tdata_put(struct tdata *tdata)
-{
- spin_unlock(&task_list_lock);
-}
-
-
-
-
-
-/* ============================================================================
- * = do_exit =
- * ============================================================================
- */
-static int do_exit_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct tdata *tdata;
-
- tdata = tdata_get(current);
- if (tdata)
- tdata_destroy(tdata);
-
- return 0;
-}
-
-struct kprobe do_exit_kp = {
- .pre_handler = do_exit_handler,
-};
-
-int tdata_enable(void)
-{
- int ret;
-
- ret = swap_register_kprobe(&do_exit_kp);
- if (ret)
- return ret;
-
- return ret;
-}
-
-void tdata_disable(void)
-{
- swap_unregister_kprobe(&do_exit_kp);
-
- spin_lock(&task_list_lock);
- priv_tdata_destroy_all();
- spin_unlock(&task_list_lock);
-}
-
-int tdata_once(void)
-{
- const char *sym;
-
- sym = "do_exit";
- do_exit_kp.addr = (void *)swap_ksyms(sym);
- if (do_exit_kp.addr == NULL)
- goto not_found;
-
- return 0;
-
-not_found:
- nsp_print("ERROR: symbol '%s' not found\n", sym);
- return -ESRCH;
-}
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#ifndef _NSP_TDATA_H
-#define _NSP_TDATA_H
-
-
-#include <linux/types.h>
-#include <us_manager/probes/probe_info_new.h>
-
-
-enum nsp_proc_stat {
- NPS_OPEN_E, /* mapping begin */
- NPS_OPEN_R,
- NPS_SYM_E,
- NPS_SYM_R, /* mapping end */
- NPS_MAIN_E, /* main begin */
- NPS_AC_EFL_MAIN_E, /* main end */
- NPS_AC_INIT_R, /* create begin */
- NPS_ELM_RUN_E, /* create end */
- NPS_DO_APP_E, /* reset begin */
- NPS_DO_APP_R /* reset end */
-};
-
-
-struct nsp_data;
-struct task_struct;
-
-
-struct tdata {
- enum nsp_proc_stat stat;
- struct nsp_data *nsp_data;
- u64 time;
- void *handle;
- struct probe_new p_main;
-};
-
-
-struct tdata *tdata_create(struct task_struct *task);
-void tdata_destroy(struct tdata *tdata);
-
-struct tdata *tdata_get(struct task_struct *task);
-void tdata_put(struct tdata *tdata);
-
-int tdata_enable(void);
-void tdata_disable(void);
-
-int tdata_once(void);
-
-
-#endif /* _NSP_TDATA_H */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_message_parser.o
-swap_message_parser-y := swap_msg_parser.o \
- msg_parser.o \
- msg_buf.o \
- msg_cmd.o \
- features.o \
- us_inst.o \
- cpu_ctrl.o \
- usm_msg.o
+++ /dev/null
-/**
- * parser/cpu_ctrl.c
- * @author Vasiliy Ulyanov <v.ulyanov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * CPU controls implementation.
- */
-
-#include <linux/cpumask.h>
-#include <linux/cpu.h>
-#include <ksyms/ksyms.h>
-
-#ifdef CONFIG_SMP
-static void (*swap_cpu_maps_update_begin)(void);
-static void (*swap_cpu_maps_update_done)(void);
-static int (*swap_cpu_down)(unsigned int, int);
-static int (*swap_cpu_up)(unsigned int, int);
-
-/**
- * @brief Disables nonboot CPUs lock.
- *
- * @param mask Pointer to CPU mask struct.
- * @return 0 on success, error code on error.
- */
-int swap_disable_nonboot_cpus_lock(struct cpumask *mask)
-{
- int boot_cpu, cpu;
- int ret = 0;
-
- swap_cpu_maps_update_begin();
- cpumask_clear(mask);
-
- boot_cpu = cpumask_first(cpu_online_mask);
-
- for_each_online_cpu(cpu) {
- if (cpu == boot_cpu)
- continue;
- ret = swap_cpu_down(cpu, 0);
- if (ret == 0)
- cpumask_set_cpu(cpu, mask);
- printk(KERN_INFO "===> SWAP CPU[%d] down(%d)\n", cpu, ret);
- }
-
- WARN_ON(num_online_cpus() > 1);
- return ret;
-}
-
-/**
- * @brief Enables nonboot CPUs unlock.
- *
- * @param mask Pointer to CPU mask struct.
- * @return 0 on success, error code on error.
- */
-int swap_enable_nonboot_cpus_unlock(struct cpumask *mask)
-{
- int cpu, ret = 0;
-
- if (cpumask_empty(mask))
- goto out;
-
- for_each_cpu(cpu, mask) {
- ret = swap_cpu_up(cpu, 0);
- printk(KERN_INFO "===> SWAP CPU[%d] up(%d)\n", cpu, ret);
- }
-
-out:
- swap_cpu_maps_update_done();
-
- return ret;
-}
-
-/**
- * @brief Intializes CPU controls.
- *
- * @return 0 on success, error code on error.
- */
-int init_cpu_deps(void)
-{
- const char *sym = "cpu_maps_update_begin";
-
- swap_cpu_maps_update_begin = (void *)swap_ksyms(sym);
- if (!swap_cpu_maps_update_begin)
- goto not_found;
-
- sym = "cpu_maps_update_done";
- swap_cpu_maps_update_done = (void *)swap_ksyms(sym);
- if (!swap_cpu_maps_update_done)
- goto not_found;
-
- sym = "_cpu_up";
- swap_cpu_up = (void *)swap_ksyms(sym);
- if (!swap_cpu_up)
- goto not_found;
-
- sym = "_cpu_down";
- swap_cpu_down = (void *)swap_ksyms(sym);
- if (!swap_cpu_down)
- goto not_found;
-
- return 0;
-
-not_found:
- printk(KERN_INFO "ERROR: symbol %s(...) not found\n", sym);
- return -ESRCH;
-}
-
-#endif /* CONFIG_SMP */
+++ /dev/null
-/**
- * @file parser/cpu_ctrl.h
- * @author Vasiliy Ulyanov <v.ulyanov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * CPU controls interface.
- */
-
-#ifndef _CPU_CTRL_H_
-#define _CPU_CTRL_H_
-
-struct cpumask;
-
-#ifdef CONFIG_SMP
-int swap_disable_nonboot_cpus_lock(struct cpumask *mask);
-int swap_enable_nonboot_cpus_unlock(struct cpumask *mask);
-
-int init_cpu_deps(void);
-
-#else /* CONFIG_SMP */
-
-static inline int swap_disable_nonboot_cpus_lock(struct cpumask *mask)
-{
- return 0;
-}
-
-static inline int swap_enable_nonboot_cpus_unlock(struct cpumask *mask)
-{
- return 0;
-}
-
-static inline int init_cpu_deps(void)
-{
- return 0;
-}
-
-#endif /* CONFIG_SMP */
-
-#endif /* _CPU_CTRL_H_ */
+++ /dev/null
-/**
- * parser/features.c
- * @author Vyacheslav Cherkashin
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Features control implementation.
- */
-
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <ks_features/ks_features.h>
-#include <us_manager/us_manager.h>
-#include "parser_defs.h"
-#include "features.h"
-#include "msg_parser.h"
-
-#include <writer/swap_msg.h>
-#include <writer/event_filter.h>
-#include <sampler/swap_sampler_module.h>
-#include <energy/energy.h>
-
-/**
- * @enum features_list
- * List of supported features.
- */
-enum features_list {
- syscall_file = (1 << 10), /**< File operation syscalls tracing */
- syscall_ipc = (1 << 11), /**< IPC syscall tracing */
- syscall_process = (1 << 12), /**< Process syscalls tracing */
- syscall_signal = (1 << 13), /**< Signal syscalls tracing */
- syscall_network = (1 << 14), /**< Network syscalls tracing */
- syscall_desc = (1 << 15), /**< Descriptor syscalls tracing */
- context_switch = (1 << 16), /**< Context switch tracing */
- func_sampling = (1 << 19) /**< Function sampling */
-};
-
-/**
- * @brief Start user-space instrumentation event handling.
- *
- * @param conf Pointer to conf_data config.
- * @return 0.
- */
-int set_us_inst(struct conf_data *conf)
-{
- set_quiet(QT_OFF);
-
- return 0;
-}
-
-/**
- * @brief Stop user-space instrumentation event handling.
- *
- * @return 0.
- */
-int unset_us_inst(void)
-{
- set_quiet(QT_ON);
-
- return 0;
-}
-
-/**
- * @brief Set syscall file feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_file(struct conf_data *conf)
-{
- int ret;
-
- ret = set_feature(FID_FILE);
-
- return ret;
-}
-
-/**
- * @brief Set syscall file feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_file(void)
-{
- int ret;
-
- ret = unset_feature(FID_FILE);
-
- return ret;
-}
-
-/**
- * @brief Set syscall ipc feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_ipc(struct conf_data *conf)
-{
- int ret;
-
- ret = set_feature(FID_IPC);
-
- return ret;
-}
-
-/**
- * @brief Set syscall ipc feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_ipc(void)
-{
- int ret;
-
- ret = unset_feature(FID_IPC);
-
- return ret;
-}
-
-/**
- * @brief Set syscall process feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_process(struct conf_data *conf)
-{
- int ret;
-
- ret = set_feature(FID_PROCESS);
-
- return ret;
-}
-
-/**
- * @brief Set syscall process feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_process(void)
-{
- int ret;
-
- ret = unset_feature(FID_PROCESS);
-
- return ret;
-}
-
-/**
- * @brief Set syscall signal feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_signal(struct conf_data *conf)
-{
- int ret;
-
- ret = set_feature(FID_SIGNAL);
-
- return ret;
-}
-
-/**
- * @brief Set syscall signal feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_signal(void)
-{
- int ret;
-
- ret = unset_feature(FID_SIGNAL);
-
- return ret;
-}
-
-/**
- * @brief Set syscall network feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_network(struct conf_data *conf)
-{
- int ret;
-
- ret = set_feature(FID_NET);
-
- return ret;
-}
-
-/**
- * @brief Set syscall network feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_network(void)
-{
- int ret;
-
- ret = unset_feature(FID_NET);
-
- return ret;
-}
-
-/**
- * @brief Set syscall desc feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_syscall_desc(struct conf_data *conf)
-{
- int ret;
-
- ret = set_feature(FID_DESC);
-
- return ret;
-}
-
-/**
- * @brief Set syscall desc feature off.
- *
- * @return unset_feature results.
- */
-int unset_syscall_desc(void)
-{
- int ret;
-
- ret = unset_feature(FID_DESC);
-
- return ret;
-}
-
-/**
- * @brief Set context switch feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_context_switch(struct conf_data *conf)
-{
- int ret;
-
- ret = set_feature(FID_SWITCH);
-
- return ret;
-}
-/**
- * @brief Set context switch feature off.
- *
- * @return unset_feature results.
- */
-int unset_context_switch(void)
-{
- int ret;
-
- ret = unset_feature(FID_SWITCH);
-
- return ret;
-}
-
-
-
-
-
-struct sample {
- u32 pid;
- u64 pc_addr;
- u32 tid;
- u32 cpu_num;
-} __packed;
-
-static void sample_msg(struct pt_regs *regs)
-{
- struct swap_msg *m;
- struct sample *s;
- struct task_struct *task = current;
-
- m = swap_msg_get(MSG_SAMPLE);
-
- s = swap_msg_payload(m);
- s->pid = task->tgid;
- s->pc_addr = instruction_pointer(regs);
- s->tid = task->pid;
- s->cpu_num = smp_processor_id();
-
- swap_msg_flush(m, sizeof(*s));
- swap_msg_put(m);
-}
-
-static void sampler_cb(struct pt_regs *regs)
-{
- if (check_event(current))
- sample_msg(regs);
-}
-
-/**
- * @brief Set sampling feature on.
- *
- * @param conf Pointer to conf_data config.
- * @return set_feature results.
- */
-int set_func_sampling(struct conf_data *conf)
-{
- int ret;
-
- ret = swap_sampler_start(conf->data_msg_period, sampler_cb);
-
- return ret;
-}
-
-/**
- * @brief Set sampling feature off.
- *
- * @return unset_feature results.
- */
-int unset_func_sampling(void)
-{
- int ret;
-
- ret = swap_sampler_stop();
-
- return ret;
-}
-
-static int set_func_energy(struct conf_data *conf)
-{
- return set_energy();
-}
-
-static int unset_func_energy(void)
-{
- return unset_energy();
-}
-
-static int set_sysfile_activity(struct conf_data *conf)
-{
- return set_feature(FID_SYSFILE_ACTIVITY);
-}
-
-static int unset_sysfile_activity(void)
-{
- return unset_feature(FID_SYSFILE_ACTIVITY);
-}
-
-/**
- * @struct feature_item
- * @brief Struct that describes feature.
- * @var feature_item::name
- * Feature name.
- * @var feature_item::set
- * Set feature callback.
- * @var feature_item::unset
- * Unset feature callback.
- */
-struct feature_item {
- char *name;
- int (*set)(struct conf_data *conf);
- int (*unset)(void);
-};
-
-static struct feature_item feature_us_inst = {
- .name = "user space instrumentation",
- .set = set_us_inst,
- .unset = unset_us_inst
-};
-
-static struct feature_item feature_syscall_file = {
- .name = "file operation syscalls",
- .set = set_syscall_file,
- .unset = unset_syscall_file
-};
-
-static struct feature_item feature_syscall_ipc = {
- .name = "IPC syscall",
- .set = set_syscall_ipc,
- .unset = unset_syscall_ipc
-};
-
-static struct feature_item feature_syscall_process = {
- .name = "process syscalls",
- .set = set_syscall_process,
- .unset = unset_syscall_process
-};
-
-static struct feature_item feature_syscall_signal = {
- .name = "signal syscalls",
- .set = set_syscall_signal,
- .unset = unset_syscall_signal
-};
-
-static struct feature_item feature_syscall_network = {
- .name = "network syscalls",
- .set = set_syscall_network,
- .unset = unset_syscall_network
-};
-
-static struct feature_item feature_syscall_desc = {
- .name = "descriptor syscalls",
- .set = set_syscall_desc,
- .unset = unset_syscall_desc
-};
-
-static struct feature_item feature_context_switch = {
- .name = "context switch",
- .set = set_context_switch,
- .unset = unset_context_switch
-};
-
-static struct feature_item feature_func_sampling = {
- .name = "function sampling",
- .set = set_func_sampling,
- .unset = unset_func_sampling
-};
-
-static struct feature_item feature_func_energy = {
- .name = "energy",
- .set = set_func_energy,
- .unset = unset_func_energy
-};
-
-static struct feature_item feature_sysfile_activity = {
- .name = "system file activity",
- .set = set_sysfile_activity,
- .unset = unset_sysfile_activity
-};
-
-static struct feature_item *feature_list[] = {
- /* 0 */ NULL,
- /* 1 */ NULL,
- /* 2 */ &feature_us_inst,
- /* 3 */ NULL,
- /* 4 */ NULL,
- /* 5 */ NULL,
- /* 6 */ NULL,
- /* 7 */ NULL,
- /* 8 */ NULL,
- /* 9 */ NULL,
- /* 10 */ &feature_syscall_file,
- /* 11 */ &feature_syscall_ipc,
- /* 12 */ &feature_syscall_process,
- /* 13 */ &feature_syscall_signal,
- /* 14 */ &feature_syscall_network,
- /* 15 */ &feature_syscall_desc,
- /* 16 */ &feature_context_switch,
- /* 17 */ NULL,
- /* 18 */ NULL,
- /* 19 */ &feature_func_sampling,
- /* 20 */ NULL,
- /* 21 */ NULL,
- /* 22 */ NULL,
- /* 23 */ NULL,
- /* 24 */ NULL,
- /* 25 */ NULL,
- /* 26 */ &feature_func_energy,
- /* 27 */ NULL,
- /* 28 */ NULL,
- /* 29 */ NULL,
- /* 30 */ NULL,
- /* 31 */ NULL,
- /* 32 */ NULL,
- /* 33 */ NULL,
- /* 34 */ NULL,
- /* 35 */ NULL,
- /* 36 */ NULL,
- /* 37 */ NULL,
- /* 38 */ NULL,
- /* 39 */ NULL,
- /* 40 */ NULL,
- /* 41 */ NULL,
- /* 42 */ NULL,
- /* 43 */ NULL,
- /* 44 */ NULL,
- /* 45 */ NULL,
- /* 46 */ NULL,
- /* 47 */ NULL,
- /* 48 */ &feature_sysfile_activity,
-};
-
-/**
- * @brief SIZE_FEATURE_LIST definition.
- */
-enum {
- SIZE_FEATURE_LIST =
- sizeof(feature_list) / sizeof(struct feature_item *),
-};
-
-static u64 feature_inst;
-static u64 feature_mask;
-
-/**
- * @brief Inits features list.
- *
- * @return 0.
- */
-int once_features(void)
-{
- int i;
- for (i = 0; i < SIZE_FEATURE_LIST; ++i) {
- printk(KERN_INFO "### f init_feature_mask[%2d]=%p\n", i,
- feature_list[i]);
- if (feature_list[i] != NULL) {
- feature_mask |= ((u64)1) << i;
- printk(KERN_INFO "### f name=%s\n",
- feature_list[i]->name);
- }
- }
-
- return 0;
-}
-
-static int do_set_features(struct conf_data *conf)
-{
- int i, ret;
- u64 feature_XOR;
- u64 features, features_backup;
-
- /* TODO: field use_features1 is not used*/
- features_backup = features = conf->use_features0;
-
- features &= feature_mask;
- feature_XOR = features ^ feature_inst;
-
- for (i = 0; feature_XOR && i < SIZE_FEATURE_LIST; ++i) {
- if ((feature_XOR & 1) && feature_list[i] != NULL) {
- u64 f_mask;
- if (features & 1)
- ret = feature_list[i]->set(conf);
- else
- ret = feature_list[i]->unset();
-
- if (ret) {
- char *func = features & 1 ? "set" : "unset";
- print_err("%s '%s' ret=%d\n",
- func, feature_list[i]->name, ret);
-
- return ret;
- }
- f_mask = ~((u64)1 << i);
- feature_inst = (feature_inst & f_mask) |
- (features_backup & ~f_mask);
- }
-
- features >>= 1;
- feature_XOR >>= 1;
- }
-
- return 0;
-}
-
-static DEFINE_MUTEX(mutex_features);
-
-/**
- * @brief Wrapper for do_set_features with locking.
- *
- * @param conf Pointer to the current config.
- * @return do_set_features result.
- */
-int set_features(struct conf_data *conf)
-{
- int ret;
-
- mutex_lock(&mutex_features);
- ret = do_set_features(conf);
- mutex_unlock(&mutex_features);
-
- return ret;
-}
+++ /dev/null
-/**
- * @file parser/features.h
- * @author Vyacheslav Cherkashin
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Features control interface declaration.
- */
-
-
-#ifndef _FEATURES_H
-#define _FEATURES_H
-
-struct conf_data;
-
-int once_features(void);
-
-int set_features(struct conf_data *conf);
-
-#endif /* _FEATURES_H */
+++ /dev/null
-/**
- * parser/msg_buf.c
- * @author Vyacheslav Cherkashin
- * @author Vitaliy Cherepanov
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Message buffer controls implementation.
- */
-
-
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include "msg_buf.h"
-#include "parser_defs.h"
-
-/**
- * @brief Initializes message buffer.
- *
- * @param mb Pointer to message buffer struct.
- * @param size Size of the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int init_mb(struct msg_buf *mb, size_t size)
-{
- if (size) {
- mb->begin = vmalloc(size);
- if (mb->begin == NULL) {
- printk(KERN_INFO "Cannot alloc memory!\n");
- return -ENOMEM;
- }
-
- mb->ptr = mb->begin;
- mb->end = mb->begin + size;
- } else
- mb->begin = mb->end = mb->ptr = NULL;
-
- return 0;
-}
-
-/**
- * @brief Uninitializes message buffer.
- *
- * @param mb Pointer to message buffer struct.
- * @return Void.
- */
-void uninit_mb(struct msg_buf *mb)
-{
- vfree(mb->begin);
-}
-
-/**
- * @brief Checks if current buffer data pointer is at the end.
- *
- * @param mb Pointer to the message buffer struct.
- * @param size Size of the message buffer.
- * @return 1 - buffer ptr is not at the end,
- * 0 - buffer ptr is at the end,
- * -1 - buffer ptr is invalid (far away of the end).
- */
-int cmp_mb(struct msg_buf *mb, size_t size)
-{
- char *tmp;
-
- tmp = mb->ptr + size;
- if (mb->end > tmp)
- return 1;
- else if (mb->end < tmp)
- return -1;
-
- return 0;
-}
-
-/**
- * @brief Gets remainder part of message buffer.
- *
- * @param mb Pointer to the message buffer struct.
- * @return Remainder part of message buffer.
- */
-size_t remained_mb(struct msg_buf *mb)
-{
- return mb->end - mb->ptr;
-}
-
-/**
- * @brief Checks whether we reached the end of the message buffer or not.
- *
- * @param mb Pointer to the message buffer struct.
- * @return 1 - if message buffer end has been reached \n
- * 0 - otherwise.
- */
-int is_end_mb(struct msg_buf *mb)
-{
- return mb->ptr == mb->end;
-}
-
-/**
- * @brief Reads 8 bits from message buffer and updates buffer's pointer.
- *
- * @param mb Pointer to the message buffer struct.
- * @param val Pointer to the target variable where to put read value.
- * @return 0 on success, negative error code on error.
- */
-int get_u8(struct msg_buf *mb, u8 *val)
-{
- if (cmp_mb(mb, sizeof(*val)) < 0)
- return -EINVAL;
-
- *val = *((u8 *)mb->ptr);
- mb->ptr += sizeof(*val);
-
- print_parse_debug("u8 ->%d;%08X\n", *val, *val);
-
- return 0;
-}
-
-/**
- * @brief Reads 32 bits from message buffer and updates buffer's pointer.
- *
- * @param mb Pointer to the message buffer struct.
- * @param val Pointer to the target variable where to put read value.
- * @return 0 on success, negative error code on error.
- */
-int get_u32(struct msg_buf *mb, u32 *val)
-{
- if (cmp_mb(mb, sizeof(*val)) < 0)
- return -EINVAL;
-
- *val = *((u32 *)mb->ptr);
- mb->ptr += sizeof(*val);
-
- print_parse_debug("u32->%d;%08X\n", *val, *val);
-
- return 0;
-}
-
-/**
- * @brief Reads 64 bits from message buffer and updates buffer's pointer.
- *
- * @param mb Pointer to the message buffer struct.
- * @param val Pointer to the target variable where to put read value.
- * @return 0 on success, negative error code on error.
- */
-int get_u64(struct msg_buf *mb, u64 *val)
-{
- if (cmp_mb(mb, sizeof(*val)) < 0)
- return -EINVAL;
-
- *val = *((u64 *)mb->ptr);
- mb->ptr += sizeof(*val);
- print_parse_debug("u64->%llu; 0x%016llX\n", *val, *val);
-
- return 0;
-}
-
-/**
- * @brief Reads null-terminated string from message buffer and updates
- * buffer's pointer.
- *
- * @param mb Pointer to the message buffer struct.
- * @param str Pointer to the target variable where to put read string.
- * @return 0 on success, negative error code on error.
- */
-int get_string(struct msg_buf *mb, char **str)
-{
- size_t len, len_max;
- enum { min_len_str = 1 };
-
- if (cmp_mb(mb, min_len_str) < 0)
- return -EINVAL;
-
- len_max = remained_mb(mb) - 1;
- len = strnlen(mb->ptr, len_max);
-
- *str = kmalloc(len + 1, GFP_KERNEL);
- if (*str == NULL)
- return -ENOMEM;
-
- memcpy(*str, mb->ptr, len);
- (*str)[len] = '\0';
-
- mb->ptr += len + 1;
-
- print_parse_debug("str->'%s'\n", *str);
- return 0;
-}
-
-/**
- * @brief Releases string memory allocated in get_string.
- *
- * @param str Pointer to the target string.
- * @return Void.
- */
-void put_string(char *str)
-{
- kfree(str);
-}
+++ /dev/null
-/**
- * @file parser/msg_buf.h
- * @author Vyacheslav Cherkashin
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Message buffer interface declaration.
- */
-
-
-#ifndef _MSG_BUF_H
-#define _MSG_BUF_H
-
-#include <linux/types.h>
-
-/**
- * @struct msg_buf
- * @brief Stores pointers to the message buffer.
- */
-struct msg_buf {
- char *begin; /**< Pointer to the beginning of the buffer. */
- char *end; /**< Pointer to the end of the buffer. */
- char *ptr; /**< Buffer iterator. */
-};
-
-int init_mb(struct msg_buf *mb, size_t size);
-void uninit_mb(struct msg_buf *mb);
-
-int cmp_mb(struct msg_buf *mb, size_t size);
-size_t remained_mb(struct msg_buf *mb);
-int is_end_mb(struct msg_buf *mb);
-
-int get_u8(struct msg_buf *mb, u8 *val);
-int get_u32(struct msg_buf *mb, u32 *val);
-int get_u64(struct msg_buf *mb, u64 *val);
-
-int get_string(struct msg_buf *mb, char **str);
-void put_string(char *str);
-
-#endif /* _MSG_BUF_H */
+++ /dev/null
-/**
- * parser/msg_cmd.c
- * @author Vyacheslav Cherkashin
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Module's messages parsing implementation.
- */
-
-
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include "msg_parser.h"
-#include "msg_buf.h"
-#include "features.h"
-#include "parser_defs.h"
-#include "us_inst.h"
-#include <writer/swap_msg.h>
-#include <us_manager/us_manager.h>
-
-
-static int wrt_launcher_port;
-
-static int set_config(struct conf_data *conf)
-{
- int ret;
-
- ret = set_features(conf);
-
- return ret;
-}
-
-/**
- * @brief Message "keep alive" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_keep_alive(struct msg_buf *mb)
-{
- if (!is_end_mb(mb)) {
- print_err("to long message, remained=%u", remained_mb(mb));
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * @brief Message "start" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_start(struct msg_buf *mb)
-{
- int ret = 0;
- struct us_inst_data *us_inst;
- struct conf_data conf;
-
- swap_msg_seq_num_reset();
- swap_msg_discard_reset();
-
- us_inst = create_us_inst_data(mb);
- if (us_inst == NULL)
- return -EINVAL;
-
- if (!is_end_mb(mb)) {
- print_err("to long message, remained=%u", remained_mb(mb));
- ret = -EINVAL;
- goto free_us_inst;
- }
-
- ret = mod_us_inst(us_inst, MT_ADD);
- if (ret) {
- printk(KERN_INFO "Cannot mod us inst, ret = %d\n", ret);
- ret = -EINVAL;
- goto free_us_inst;
- }
-
- ret = usm_start();
- if (ret)
- goto free_us_inst;
-
- restore_config(&conf);
- set_config(&conf);
-
-free_us_inst:
- destroy_us_inst_data(us_inst);
-
- return ret;
-}
-
-/**
- * @brief Message "stop" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_stop(struct msg_buf *mb)
-{
- int ret = 0;
- struct conf_data conf;
- int discarded;
-
- if (!is_end_mb(mb)) {
- print_err("to long message, remained=%u", remained_mb(mb));
- return -EINVAL;
- }
-
- ret = usm_stop();
- if (ret)
- return ret;
-
- pfg_put_all();
-
- conf.use_features0 = 0;
- conf.use_features1 = 0;
- ret = set_config(&conf);
- if (ret)
- printk(KERN_INFO "Cannot set config, ret = %d\n", ret);
-
- discarded = swap_msg_discard_get();
- printk(KERN_INFO "discarded messages: %d\n", discarded);
- swap_msg_discard_reset();
-
- return ret;
-}
-
-/**
- * @brief Message "config" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_config(struct msg_buf *mb)
-{
- int ret = 0;
- struct conf_data *conf;
- enum status_type st;
-
- conf = create_conf_data(mb);
- if (conf == NULL)
- return -EINVAL;
-
- if (!is_end_mb(mb)) {
- print_err("to long message, remained=%u", remained_mb(mb));
- ret = -EINVAL;
- goto free_conf_data;
- }
-
- st = usm_get_status();
- if (st == ST_ON)
- set_config(conf);
-
- save_config(conf);
- usm_put_status(st);
-
-free_conf_data:
- destroy_conf_data(conf);
-
- return ret;
-}
-
-/**
- * @brief Message "swap inst add" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_swap_inst_add(struct msg_buf *mb)
-{
- int ret = 0;
- struct us_inst_data *us_inst;
-
- us_inst = create_us_inst_data(mb);
- if (us_inst == NULL)
- return -EINVAL;
-
- if (!is_end_mb(mb)) {
- print_err("to long message, remained=%u", remained_mb(mb));
- ret = -EINVAL;
- goto free_us_inst;
- }
-
- ret = mod_us_inst(us_inst, MT_ADD);
-
-free_us_inst:
- destroy_us_inst_data(us_inst);
-
- return ret;
-}
-
-/**
- * @brief Message "swap inst remove" handling.
- *
- * @param mb Pointer to the message buffer.
- * @return 0 on success, negative error code on error.
- */
-int msg_swap_inst_remove(struct msg_buf *mb)
-{
- int ret = 0;
- struct us_inst_data *us_inst;
-
- us_inst = create_us_inst_data(mb);
- if (us_inst == NULL)
- return -EINVAL;
-
- if (!is_end_mb(mb)) {
- print_err("to long message, remained=%u", remained_mb(mb));
- ret = -EINVAL;
- goto free_us_inst;
- }
-
- ret = mod_us_inst(us_inst, MT_DEL);
-
-free_us_inst:
- destroy_us_inst_data(us_inst);
-
- return ret;
-}
-
-void set_wrt_launcher_port(int port)
-{
- wrt_launcher_port = port;
-}
-EXPORT_SYMBOL_GPL(set_wrt_launcher_port);
-
-#define GET_PORT_DELAY 100 /* msec */
-#define GET_PORT_TIMEOUT 10000 /* msec */
-
-int get_wrt_launcher_port(void)
-{
- int port;
- int timeout = GET_PORT_TIMEOUT;
-
- do {
- port = wrt_launcher_port;
- timeout -= GET_PORT_DELAY;
- mdelay(GET_PORT_DELAY);
- } while (!port && timeout > 0);
-
- set_wrt_launcher_port(0);
-
- return port;
-}
-
-/**
- * @brief Initializes commands handling.
- *
- * @return Initialization results.
- */
-int once_cmd(void)
-{
- return once_features();
-}
+++ /dev/null
-/**
- * @file parser/msg_cmd.h
- * @author Vyacheslav Cherkashin
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Module's message handling interface declaration.
- */
-
-#ifndef _MSG_CMD_H
-#define _MSG_CMD_H
-
-struct msg_buf;
-
-int once_cmd(void);
-
-int msg_keep_alive(struct msg_buf *mb);
-int msg_start(struct msg_buf *mb);
-int msg_stop(struct msg_buf *mb);
-int msg_config(struct msg_buf *mb);
-int msg_swap_inst_add(struct msg_buf *mb);
-int msg_swap_inst_remove(struct msg_buf *mb);
-int get_wrt_launcher_port(void);
-void set_wrt_launcher_port(int port);
-
-#endif /* _MSG_CMD_H */
+++ /dev/null
-/**
- * parser/msg_parser.c
- *
- * @author Vyacheslav Cherkashin
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @sectionLICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Message parsing implementation.
- */
-
-
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <us_manager/probes/probes.h>
-#include "msg_parser.h"
-#include "msg_buf.h"
-#include "parser_defs.h"
-
-
-static int str_to_u32(const char *str, u32 *val)
-{
- u32 result;
- if (!str || !*str)
- return -EINVAL;
-
- for (result = 0 ; *str; ++str) {
- if (*str < '0' || *str > '9')
- return -EINVAL;
-
- result = result * 10 + (*str - '0');
- }
-
- *val = result;
-
- return 0;
-}
-
-
-
-
-
-/* ============================================================================
- * == APP_INFO ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills app_info_data struct.
- *
- * @param mb Pointer to the message buffer.
- * @return Pointer to the filled app_info_data struct on success;\n
- * NULL on error.
- */
-struct app_info_data *create_app_info(struct msg_buf *mb)
-{
- int ret;
- struct app_info_data *ai;
- u32 app_type;
- char *ta_id, *exec_path;
-
- print_parse_debug("app_info:\n");
-
- print_parse_debug("type:");
- ret = get_u32(mb, &app_type);
- if (ret) {
- print_err("failed to read target application type\n");
- return NULL;
- }
-
- print_parse_debug("id:");
- ret = get_string(mb, &ta_id);
- if (ret) {
- print_err("failed to read target application ID\n");
- return NULL;
- }
-
- print_parse_debug("exec path:");
- ret = get_string(mb, &exec_path);
- if (ret) {
- print_err("failed to read executable path\n");
- goto free_ta_id;
- }
-
- ai = kmalloc(sizeof(*ai), GFP_KERNEL);
- if (ai == NULL) {
- print_err("out of memory\n");
- goto free_exec_path;
- }
-
- switch (app_type) {
- case AT_TIZEN_NATIVE_APP:
- case AT_TIZEN_WEB_APP:
- case AT_COMMON_EXEC:
- ai->tgid = 0;
- break;
- case AT_PID: {
- u32 tgid = 0;
-
- if (*ta_id != '\0') {
- ret = str_to_u32(ta_id, &tgid);
- if (ret) {
- print_err("converting string to PID, "
- "str='%s'\n", ta_id);
- goto free_ai;
- }
- }
-
- ai->tgid = tgid;
- break;
- }
- default:
- print_err("wrong application type(%u)\n", app_type);
- ret = -EINVAL;
- goto free_ai;
- }
-
- ai->app_type = (enum APP_TYPE)app_type;
- ai->app_id = ta_id;
- ai->exec_path = exec_path;
-
- return ai;
-
-free_ai:
- kfree(ai);
-
-free_exec_path:
- put_string(exec_path);
-
-free_ta_id:
- put_string(ta_id);
-
- return NULL;
-}
-
-/**
- * @brief app_info_data cleanup.
- *
- * @param ai Pointer to the target app_info_data.
- * @return Void.
- */
-void destroy_app_info(struct app_info_data *ai)
-{
- put_string(ai->exec_path);
- put_string(ai->app_id);
- kfree(ai);
-}
-
-
-
-
-
-/* ============================================================================
- * == CONFIG ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills conf_data struct.
- *
- * @param mb Pointer to the message buffer.
- * @return Pointer to the filled conf_data struct on success;\n
- * 0 on error.
- */
-struct conf_data *create_conf_data(struct msg_buf *mb)
-{
- struct conf_data *conf;
- u64 use_features0, use_features1;
- u32 stp, dmp;
-
- print_parse_debug("conf_data:\n");
-
- print_parse_debug("features:");
- if (get_u64(mb, &use_features0)) {
- print_err("failed to read use_features\n");
- return NULL;
- }
-
- if (get_u64(mb, &use_features1)) {
- print_err("failed to read use_features\n");
- return NULL;
- }
-
- print_parse_debug("sys trace period:");
- if (get_u32(mb, &stp)) {
- print_err("failed to read sys trace period\n");
- return NULL;
- }
-
- print_parse_debug("data msg period:");
- if (get_u32(mb, &dmp)) {
- print_err("failed to read data message period\n");
- return NULL;
- }
-
- conf = kmalloc(sizeof(*conf), GFP_KERNEL);
- if (conf == NULL) {
- print_err("out of memory\n");
- return NULL;
- }
-
- conf->use_features0 = use_features0;
- conf->use_features1 = use_features1;
- conf->sys_trace_period = stp;
- conf->data_msg_period = dmp;
-
- return conf;
-}
-
-/**
- * @brief conf_data cleanup.
- *
- * @param conf Pointer to the target conf_data.
- * @return Void.
- */
-void destroy_conf_data(struct conf_data *conf)
-{
- kfree(conf);
-}
-
-static struct conf_data config;
-
-/**
- * @brief Saves config to static config variable.
- *
- * @param conf Variable to save.
- * @return Void.
- */
-void save_config(const struct conf_data *conf)
-{
- memcpy(&config, conf, sizeof(config));
-}
-
-/**
- * @brief Restores config from static config variable.
- *
- * @param conf Variable to restore.
- * @return Void.
- */
-void restore_config(struct conf_data *conf)
-{
- memcpy(conf, &config, sizeof(*conf));
-}
-
-
-
-/* ============================================================================
- * == PROBES PARSING ==
- * ============================================================================
- */
-
-/**
- * @brief Gets retprobe data and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pi Pointer to the probe_info struct.
- * @return 0 on success, error code on error.
- */
-int get_retprobe(struct msg_buf *mb, struct probe_info *pi)
-{
- char *args;
- char ret_type;
-
- print_parse_debug("funct args:");
- if (get_string(mb, &args)) {
- print_err("failed to read data function arguments\n");
- return -EINVAL;
- }
-
- print_parse_debug("funct ret type:");
- if (get_u8(mb, (u8 *)&ret_type)) {
- print_err("failed to read data function arguments\n");
- goto free_args;
- }
-
- pi->probe_type = SWAP_RETPROBE;
- pi->size = 0;
- pi->rp_i.args = args;
- pi->rp_i.ret_type = ret_type;
-
- return 0;
-
-free_args:
- put_string(args);
- return -EINVAL;
-}
-
-/**
- * @brief Gets webprobe data and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pi Pointer to the probe_info struct.
- * @return 0 on success, error code on error.
- */
-int get_webprobe(struct msg_buf *mb, struct probe_info *pi)
-{
- pi->probe_type = SWAP_WEBPROBE;
- pi->size = 0;
-
- return 0;
-}
-
-/**
- * @brief Retprobe data cleanup.
- *
- * @param pi Pointer to the probe_info comprising retprobe.
- * @return Void.
- */
-void put_retprobe(struct probe_info *pi)
-{
- put_string(pi->rp_i.args);
-}
-
-/**
- * @brief Gets preload data and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pi Pointer to the probe_info struct.
- * @return 0 on success, error code on error.
- */
-int get_preload_probe(struct msg_buf *mb, struct probe_info *pi)
-{
- u64 handler;
- u8 flags;
-
- print_parse_debug("funct handler:");
- if (get_u64(mb, &handler)) {
- print_err("failed to read function handler\n");
- return -EINVAL;
- }
-
- print_parse_debug("collect events flag:");
- if (get_u8(mb, &flags)) {
- print_err("failed to read collect events type\n");
- return -EINVAL;
- }
-
- pi->probe_type = SWAP_PRELOAD_PROBE;
- pi->size = 0;
- pi->pl_i.handler = handler;
- pi->pl_i.flags = flags;
-
- return 0;
-}
-
-/**
- * @brief Preload probe data cleanup.
- *
- * @param pi Pointer to the probe_info comprising retprobe.
- * @return Void.
- */
-void put_preload_probe(struct probe_info *pi)
-{
-}
-
-/**
- * @brief Gets preload get_caller and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pi Pointer to the probe_info struct.
- * @return 0 on success, error code on error.
- */
-
-int get_get_caller_probe(struct msg_buf *mb, struct probe_info *pi)
-{
- pi->probe_type = SWAP_GET_CALLER;
- pi->size = 0;
-
- return 0;
-}
-
-/**
- * @brief Preload get_caller probe data cleanup.
- *
- * @param pi Pointer to the probe_info comprising retprobe.
- * @return Void.
- */
-void put_get_caller_probe(struct probe_info *pi)
-{
-}
-
-/**
- * @brief Gets preload get_call_type and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pi Pointer to the probe_info struct.
- * @return 0 on success, error code on error.
- */
-int get_get_call_type_probe(struct msg_buf *mb, struct probe_info *pi)
-{
- pi->probe_type = SWAP_GET_CALL_TYPE;
- pi->size = 0;
-
- return 0;
-}
-
-/**
- * @brief Preload get_call type probe data cleanup.
- *
- * @param pi Pointer to the probe_info comprising retprobe.
- * @return Void.
- */
-void put_get_call_type_probe(struct probe_info *pi)
-{
-}
-
-/**
- * @brief Gets preload write_msg and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pi Pointer to the probe_info struct.
- * @return 0 on success, error code on error.
- */
-int get_write_msg_probe(struct msg_buf *mb, struct probe_info *pi)
-{
- pi->probe_type = SWAP_WRITE_MSG;
- pi->size = 0;
-
- return 0;
-}
-
-/**
- * @brief Preload write_msg type probe data cleanup.
- *
- * @param pi Pointer to the probe_info comprising retprobe.
- * @return Void.
- */
-void put_write_msg_probe(struct probe_info *pi)
-{
-}
-
-
-
-
-/**
- * @brief Gets FBI probe data and puts it to the probe_info struct.
- *
- * @param mb Pointer to the message buffer.
- * @param pi Pointer to the probe_info struct.
- * @return 0 on success, error code on error.
- */
-int get_fbi_data(struct msg_buf *mb, struct fbi_var_data *vd)
-{
- u64 var_id;
- u64 reg_offset;
- u8 reg_n;
- u32 data_size;
- u8 steps_count, i;
- struct fbi_step *steps = NULL;
-
- print_parse_debug("var ID:");
- if (get_u64(mb, &var_id)) {
- print_err("failed to read var ID\n");
- return -EINVAL;
- }
-
- print_parse_debug("register offset:");
- if (get_u64(mb, ®_offset)) {
- print_err("failed to read register offset\n");
- return -EINVAL;
- }
-
- print_parse_debug("register number:");
- if (get_u8(mb, ®_n)) {
- print_err("failed to read number of the register\n");
- return -EINVAL;
- }
-
- print_parse_debug("data size:");
- if (get_u32(mb, &data_size)) {
- print_err("failed to read data size\n");
- return -EINVAL;
- }
-
- print_parse_debug("steps count:");
- if (get_u8(mb, &steps_count)) {
- print_err("failed to read steps count\n");
- return -EINVAL;
- }
-
- if (steps_count > 0) {
- steps = kmalloc(steps_count * sizeof(*vd->steps),
- GFP_KERNEL);
- if (steps == NULL) {
- print_err("MALLOC FAIL\n");
- return -ENOMEM;
- }
-
- for (i = 0; i != steps_count; i++) {
- print_parse_debug("steps #%d ptr_order:", i);
- if (get_u8(mb, &(steps[i].ptr_order))) {
- print_err("failed to read pointer order(step #%d)\n",
- i);
- goto free_steps;
- }
- print_parse_debug("steps #%d data_offset:", i);
- if (get_u64(mb, &(steps[i].data_offset))){
- print_err("failed to read offset (steps #%d)\n",
- i);
- goto free_steps;
- }
- }
- }
-
- vd->reg_n = reg_n;
- vd->reg_offset = reg_offset;
- vd->data_size = data_size;
- vd->var_id = var_id;
- vd->steps_count = steps_count;
- vd->steps = steps;
-
- return 0;
-
-free_steps:
- kfree(steps);
- return -EINVAL;
-}
-
-int get_fbi_probe(struct msg_buf *mb, struct probe_info *pi)
-{
- uint8_t var_count, i;
- struct fbi_var_data *vars;
-
- print_parse_debug("var count:");
- if (get_u8(mb, &var_count)) {
- print_err("failed to read var ID\n");
- return -EINVAL;
- }
-
- vars = kmalloc(var_count * sizeof(*vars), GFP_KERNEL);
- if (vars == NULL) {
- print_err("alloc vars error\n");
- goto err;
- }
-
- for (i = 0; i != var_count; i++) {
- if (get_fbi_data(mb, &vars[i]) != 0)
- goto free_vars;
- }
-
- pi->probe_type = SWAP_FBIPROBE;
- pi->fbi_i.var_count = var_count;
- pi->fbi_i.vars = vars;
- pi->size =0 ;
- return 0;
-
-free_vars:
- kfree(vars);
-
-err:
- return -EINVAL;
-
-}
-
-/**
- * @brief FBI probe data cleanup.
- *
- * @param pi Pointer to the probe_info comprising FBI probe.
- * @return Void.
- */
-void put_fbi_probe(struct probe_info *pi)
-{
- return;
-}
-
-
-/* ============================================================================
- * == FUNC_INST ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills func_inst_data struct.
- *
- * @param mb Pointer to the message buffer.
- * @return Pointer to the filled func_inst_data struct on success;\n
- * 0 on error.
- */
-struct func_inst_data *create_func_inst_data(struct msg_buf *mb)
-{
- struct func_inst_data *fi;
- u64 addr;
- u8 type;
-
- print_parse_debug("func addr:");
- if (get_u64(mb, &addr)) {
- print_err("failed to read data function address\n");
- return NULL;
- }
-
- print_parse_debug("probe type:");
- if (get_u8(mb, &type)) {
- print_err("failed to read data probe type\n");
- return NULL;
- }
-
- fi = kmalloc(sizeof(*fi), GFP_KERNEL);
- if (fi == NULL) {
- print_err("out of memory\n");
- return NULL;
- }
-
- fi->addr = addr;
-
- switch (type) {
- case SWAP_RETPROBE:
- if (get_retprobe(mb, &(fi->probe_i)) != 0)
- goto free_func_inst;
- break;
- case SWAP_WEBPROBE:
- if (get_webprobe(mb, &(fi->probe_i)) != 0)
- goto free_func_inst;
- break;
- case SWAP_PRELOAD_PROBE:
- if (get_preload_probe(mb, &(fi->probe_i)) != 0)
- goto free_func_inst;
- break;
- case SWAP_GET_CALLER:
- if (get_get_caller_probe(mb, &(fi->probe_i)) != 0)
- goto free_func_inst;
- break;
- case SWAP_GET_CALL_TYPE:
- if (get_get_call_type_probe(mb, &(fi->probe_i)) != 0)
- goto free_func_inst;
- break;
- case SWAP_FBIPROBE:
- if (get_fbi_probe(mb, &(fi->probe_i)) != 0)
- goto free_func_inst;
- break;
- case SWAP_WRITE_MSG:
- if (get_write_msg_probe(mb, &(fi->probe_i)) != 0)
- goto free_func_inst;
- break;
- default:
- printk(KERN_WARNING "SWAP PARSER: Wrong probe type %d!\n",
- type);
- goto free_func_inst;
- }
-
- return fi;
-
-free_func_inst:
-
- kfree(fi);
- return NULL;
-}
-
-/**
- * @brief func_inst_data cleanup.
- *
- * @param fi Pointer to the target func_inst_data.
- * @return Void.
- */
-void destroy_func_inst_data(struct func_inst_data *fi)
-{
- switch (fi->probe_i.probe_type) {
- case SWAP_RETPROBE:
- put_retprobe(&(fi->probe_i));
- break;
- case SWAP_WEBPROBE:
- break;
- case SWAP_PRELOAD_PROBE:
- put_preload_probe(&(fi->probe_i));
- break;
- case SWAP_GET_CALLER:
- put_get_caller_probe(&(fi->probe_i));
- break;
- case SWAP_GET_CALL_TYPE:
- put_get_call_type_probe(&(fi->probe_i));
- break;
- case SWAP_FBIPROBE:
- put_fbi_probe(&(fi->probe_i));
- break;
- case SWAP_WRITE_MSG:
- put_write_msg_probe(&(fi->probe_i));
- break;
- default:
- printk(KERN_WARNING "SWAP PARSER: Wrong probe type %d!\n",
- fi->probe_i.probe_type);
- }
-
- kfree(fi);
-}
-
-
-
-
-
-/* ============================================================================
- * == LIB_INST ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills lib_inst_data struct.
- *
- * @param mb Pointer to the message buffer.
- * @return Pointer to the filled lib_inst_data struct on success;\n
- * 0 on error.
- */
-struct lib_inst_data *create_lib_inst_data(struct msg_buf *mb)
-{
- struct lib_inst_data *li;
- struct func_inst_data *fi;
- char *path;
- u32 cnt, j, i = 0;
-
- print_parse_debug("bin path:");
- if (get_string(mb, &path)) {
- print_err("failed to read path of binary\n");
- return NULL;
- }
-
- print_parse_debug("func count:");
- if (get_u32(mb, &cnt)) {
- print_err("failed to read count of functions\n");
- goto free_path;
- }
-
- if (remained_mb(mb) / MIN_SIZE_FUNC_INST < cnt) {
- print_err("to match count of functions(%u)\n", cnt);
- goto free_path;
- }
-
- li = kmalloc(sizeof(*li), GFP_KERNEL);
- if (li == NULL) {
- print_err("out of memory\n");
- goto free_path;
- }
-
- if (cnt) {
- li->func = vmalloc(sizeof(*li->func) * cnt);
- if (li->func == NULL) {
- print_err("out of memory\n");
- goto free_li;
- }
-
- for (i = 0; i < cnt; ++i) {
- print_parse_debug("func #%d:\n", i + 1);
- fi = create_func_inst_data(mb);
- if (fi == NULL)
- goto free_func;
-
- li->func[i] = fi;
- }
- } else {
- li->func = NULL;
- }
-
- li->path = path;
- li->cnt_func = cnt;
-
- return li;
-
-free_func:
- for (j = 0; j < i; ++j)
- destroy_func_inst_data(li->func[j]);
- vfree(li->func);
-
-free_li:
- kfree(li);
-
-free_path:
- put_string(path);
-
- return NULL;
-}
-
-/**
- * @brief lib_inst_data cleanup.
- *
- * @param li Pointer to the target lib_inst_data.
- * @return Void.
- */
-void destroy_lib_inst_data(struct lib_inst_data *li)
-{
- int i;
-
- put_string(li->path);
-
- for (i = 0; i < li->cnt_func; ++i)
- destroy_func_inst_data(li->func[i]);
-
- vfree(li->func);
- kfree(li);
-}
-
-
-
-
-
-/* ============================================================================
- * == APP_INST ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills app_inst_data struct.
- *
- * @param mb Pointer to the message buffer.
- * @return Pointer to the filled app_inst_data struct on success;\n
- * 0 on error.
- */
-struct app_inst_data *create_app_inst_data(struct msg_buf *mb)
-{
- struct app_inst_data *app_inst;
- struct app_info_data *app_info;
- struct func_inst_data *func;
- struct lib_inst_data *lib;
- u32 cnt_func, i_func = 0, cnt_lib, i_lib = 0, i;
-
- app_info = create_app_info(mb);
- if (app_info == NULL)
- return NULL;
-
- print_parse_debug("func count:");
- if (get_u32(mb, &cnt_func)) {
- print_err("failed to read count of functions\n");
- goto free_app_info;
- }
-
- if (remained_mb(mb) / MIN_SIZE_FUNC_INST < cnt_func) {
- print_err("to match count of functions(%u)\n", cnt_func);
- goto free_app_info;
- }
-
- app_inst = kmalloc(sizeof(*app_inst), GFP_KERNEL);
- if (app_inst == NULL) {
- print_err("out of memory\n");
- goto free_app_info;
- }
-
- if (cnt_func) {
- app_inst->func = vmalloc(sizeof(*app_inst->func) * cnt_func);
- if (app_inst->func == NULL) {
- print_err("out of memory\n");
- goto free_app_inst;
- }
-
- for (i_func = 0; i_func < cnt_func; ++i_func) {
- print_parse_debug("func #%d:\n", i_func + 1);
- func = create_func_inst_data(mb);
- if (func == NULL)
- goto free_func;
-
- app_inst->func[i_func] = func;
- }
- } else {
- app_inst->func = NULL;
- }
-
- print_parse_debug("lib count:");
- if (get_u32(mb, &cnt_lib)) {
- print_err("failed to read count of libraries\n");
- goto free_func;
- }
-
- if (remained_mb(mb) / MIN_SIZE_LIB_INST < cnt_lib) {
- print_err("to match count of libraries(%u)\n", cnt_lib);
- goto free_func;
- }
-
- if (cnt_lib) {
- app_inst->lib = vmalloc(sizeof(*app_inst->lib) * cnt_lib);
- if (app_inst->lib == NULL) {
- print_err("out of memory\n");
- goto free_func;
- }
-
- for (i_lib = 0; i_lib < cnt_lib; ++i_lib) {
- print_parse_debug("lib #%d:\n", i_lib + 1);
- lib = create_lib_inst_data(mb);
- if (lib == NULL)
- goto free_lib;
-
- app_inst->lib[i_lib] = lib;
- }
- } else {
- app_inst->lib = NULL;
- }
-
- app_inst->app_info = app_info;
- app_inst->cnt_func = cnt_func;
- app_inst->cnt_lib = cnt_lib;
-
- return app_inst;
-
-free_lib:
- for (i = 0; i < i_lib; ++i)
- destroy_lib_inst_data(app_inst->lib[i]);
- vfree(app_inst->lib);
-
-free_func:
- for (i = 0; i < i_func; ++i)
- destroy_func_inst_data(app_inst->func[i]);
- vfree(app_inst->func);
-
-free_app_inst:
- kfree(app_inst);
-
-free_app_info:
- destroy_app_info(app_info);
-
- return NULL;
-}
-
-/**
- * @brief app_inst_data cleanup.
- *
- * @param ai Pointer to the target app_inst_data.
- * @return Void.
- */
-void destroy_app_inst_data(struct app_inst_data *ai)
-{
- int i;
-
- for (i = 0; i < ai->cnt_lib; ++i)
- destroy_lib_inst_data(ai->lib[i]);
- vfree(ai->lib);
-
- for (i = 0; i < ai->cnt_func; ++i)
- destroy_func_inst_data(ai->func[i]);
- vfree(ai->func);
-
- destroy_app_info(ai->app_info);
- kfree(ai);
-}
-
-
-
-
-
-/* ============================================================================
- * == US_INST ==
- * ============================================================================
- */
-
-/**
- * @brief Creates and fills us_inst_data struct.
- *
- * @param mb Pointer to the message buffer.
- * @return Pointer to the filled us_inst_data struct on success;\n
- * 0 on error.
- */
-struct us_inst_data *create_us_inst_data(struct msg_buf *mb)
-{
- struct us_inst_data *ui;
- struct app_inst_data *ai;
- u32 cnt, j, i = 0;
-
- print_parse_debug("us_inst_data:\n");
-
- print_parse_debug("app count:");
- if (get_u32(mb, &cnt)) {
- print_err("failed to read count of applications\n");
- return NULL;
- }
-
- if (remained_mb(mb) / MIN_SIZE_APP_INST < cnt) {
- print_err("to match count of applications(%u)\n", cnt);
- return NULL;
- }
-
- ui = kmalloc(sizeof(struct us_inst_data), GFP_KERNEL);
- if (ui == NULL) {
- print_err("out of memory\n");
- return NULL;
- }
-
- ui->app_inst = kmalloc(sizeof(struct app_inst_data *) * cnt,
- GFP_KERNEL);
- if (ui->app_inst == NULL) {
- print_err("out of memory\n");
- goto free_ui;
- }
-
- for (i = 0; i < cnt; ++i) {
- print_parse_debug("app #%d:\n", i + 1);
- ai = create_app_inst_data(mb);
- if (ai == NULL)
- goto free_app_inst;
-
- ui->app_inst[i] = ai;
- }
-
- ui->cnt = cnt;
-
- return ui;
-
-free_app_inst:
- for (j = 0; j < i; ++j)
- destroy_app_inst_data(ui->app_inst[j]);
- kfree(ui->app_inst);
-
-free_ui:
- kfree(ui);
-
- return NULL;
-}
-
-/**
- * @brief us_inst_data cleanup.
- *
- * @param ui Pointer to the target us_inst_data.
- * @return Void.
- */
-void destroy_us_inst_data(struct us_inst_data *ui)
-{
- int i;
-
- for (i = 0; i < ui->cnt; ++i)
- destroy_app_inst_data(ui->app_inst[i]);
-
- kfree(ui->app_inst);
- kfree(ui);
-}
+++ /dev/null
-/**
- * @file parser/msg_parser.h
- * @author Vyacheslav Cherkashin
- * @author Vitaliy Cherepanov
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Message parsing interface declaration.
- */
-
-
-#ifndef _MSG_PARSER_H
-#define _MSG_PARSER_H
-
-#include <linux/types.h>
-#include <us_manager/probes/probes.h>
-
-struct msg_buf;
-
-/**
- * @enum APP_TYPE
- * Supported application types.
- */
-enum APP_TYPE {
- AT_TIZEN_NATIVE_APP = 0x01, /**< Tizen native application. */
- AT_PID = 0x02, /**< App with specified PID. */
- AT_COMMON_EXEC = 0x03, /**< Common application. */
- AT_TIZEN_WEB_APP = 0x04 /**< Tizen web application. */
-};
-
-/**
- * @brief App type size defenition.
- */
-enum {
- SIZE_APP_TYPE = 4
-};
-
-/**
- * @struct app_info_data
- * @brief Basic application information.
- */
-struct app_info_data {
- enum APP_TYPE app_type; /**< Application type. */
- pid_t tgid; /**< Application PID. */
- char *app_id; /**< Application ID */
- char *exec_path; /**< Application execution path. */
-};
-
-/**
- * @struct conf_data
- * @brief Configuration struct.
- */
-struct conf_data {
- u64 use_features0; /**< Feature flags. */
- u64 use_features1; /**< Feature flags. */
- u32 sys_trace_period; /**< Trace period. */
- u32 data_msg_period; /**< Data message period. */
-};
-
-/**
- * @struct func_inst_data
- * @brief Application and library functions to set probes.
- */
-struct func_inst_data {
- u64 addr; /**< Function address. */
- struct probe_info probe_i; /**< Probe info. */
-};
-
-/**
- * @struct lib_inst_data
- * @brief Library struct.
- */
-struct lib_inst_data {
- char *path; /**< Library path. */
- u32 cnt_func; /**< Function probes count in this library. */
- struct func_inst_data **func; /**< Pointer to the probes array. */
-};
-
-/**
- * @struct app_inst_data
- * @brief Application struct.
- */
-struct app_inst_data {
- struct app_info_data *app_info; /**< Pointer to app_info struct. */
- u32 cnt_func; /**< Function probes count in app. */
- struct func_inst_data **func; /**< Pointer to the probes array. */
- u32 cnt_lib; /**< Libs count. */
- struct lib_inst_data **lib; /**< Pointer to the libs array. */
-};
-
-/**
- * @struct us_inst_data
- * @brief User space instrumentation struct.
- */
-struct us_inst_data {
- u32 cnt; /**< Apps count. */
- struct app_inst_data **app_inst; /**< Pointer to the apps array. */
-};
-
-
-struct app_info_data *create_app_info(struct msg_buf *mb);
-void destroy_app_info(struct app_info_data *app_info);
-
-struct conf_data *create_conf_data(struct msg_buf *mb);
-void destroy_conf_data(struct conf_data *conf);
-
-void save_config(const struct conf_data *conf);
-void restore_config(struct conf_data *conf);
-
-struct func_inst_data *create_func_inst_data(struct msg_buf *mb);
-void destroy_func_inst_data(struct func_inst_data *func_inst);
-
-struct lib_inst_data *create_lib_inst_data(struct msg_buf *mb);
-void destroy_lib_inst_data(struct lib_inst_data *lib_inst);
-
-struct app_inst_data *create_app_inst_data(struct msg_buf *mb);
-void destroy_app_inst_data(struct app_inst_data *app_inst);
-
-struct us_inst_data *create_us_inst_data(struct msg_buf *mb);
-void destroy_us_inst_data(struct us_inst_data *us_inst);
-
-
-/* empty functions for calculating size fields in structures */
-struct func_inst_data make_func_inst_data(void);
-struct lib_inst_data make_lib_inst_data(void);
-struct app_inst_data make_app_inst_data(void);
-struct us_inst_data make_us_inst_data(void);
-
-/**
- * @brief Constant defenitions.
- */
-enum {
- MIN_SIZE_STRING = 1,
- MIN_SIZE_FUNC_INST = sizeof(make_func_inst_data().addr) +
- MIN_SIZE_STRING,
- MIN_SIZE_LIB_INST = MIN_SIZE_STRING +
- sizeof(make_lib_inst_data().cnt_func),
- MIN_SIZE_APP_INFO = SIZE_APP_TYPE + MIN_SIZE_STRING + MIN_SIZE_STRING,
- MIN_SIZE_APP_INST = MIN_SIZE_APP_INFO +
- sizeof(make_app_inst_data().cnt_func) +
- sizeof(make_app_inst_data().cnt_lib),
- MIN_SIZE_US_INST = sizeof(make_us_inst_data().cnt)
-};
-
-#endif /* _MSG_PARSER_H */
+++ /dev/null
-/**
- * @file modules/parser/parser_defs.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov:
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Parser defenitions.
- */
-
-
-#ifndef __SWAP_DRIVER_DEVICE_DEFS_H__
-#define __SWAP_DRIVER_DEVICE_DEFS_H__
-
-#include <linux/kernel.h>
-
-/* #define PARSE_DEBUG */
-
-/** Prints debug message. */
-#define print_debug(msg, args...) \
- printk(KERN_DEBUG "SWAP_PARSER DEBUG : " msg, ##args)
-/** Prints info message. */
-#define print_msg(msg, args...) \
- printk(KERN_INFO "SWAP_PARSER : " msg, ##args)
-/** Prints warning message. */
-#define print_warn(msg, args...) \
- printk(KERN_WARNING "SWAP_PARSER WARNING : " msg, ##args)
-/** Prints error message. */
-#define print_err(msg, args...) \
- printk(KERN_ERR "SWAP_PARSER ERROR : " msg, ##args)
-/** Prints critical error message. */
-#define print_crit(msg, args...) \
- printk(KERN_CRIT "SWAP_PARSER CRITICAL : " msg, ##args)
-
-/* debug parse */
-#ifdef PARSE_DEBUG
-#define print_parse_debug(msg, args...) \
- printk(KERN_DEBUG "SWAP_PARSER DEBUG : " msg, ##args)
-#else
-#define print_parse_debug(msg, args...) \
- do {} while (0)
-#endif /* PARSE_DEBUG */
-
-#endif /* __SWAP_DRIVER_DEVICE_DEFS_H__ */
+++ /dev/null
-/**
- * parser/swap_msg_parser.c
- * @author Vyacheslav Cherkashin
- * @author Vitaliy Cherepanov
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Parser module interface implementation.
- */
-
-
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <linux/cpumask.h>
-#include <linux/uaccess.h>
-
-#include "parser_defs.h"
-#include "us_inst.h"
-#include "msg_buf.h"
-#include "msg_cmd.h"
-#include "usm_msg.h"
-#include "cpu_ctrl.h"
-
-#include <driver/driver_to_msg.h>
-#include <driver/swap_ioctl.h>
-#include <master/swap_initializer.h>
-
-/**
- * @enum MSG_ID
- * @brief Message IDs.
- */
-enum MSG_ID {
- MSG_KEEP_ALIVE = 0x0001, /**< Keep alive message. */
- MSG_START = 0x0002, /**< Start message. */
- MSG_STOP = 0x0003, /**< Stop message. */
- MSG_CONFIG = 0x0004, /**< Config message. */
- MSG_SWAP_INST_ADD = 0x0008, /**< Swap inst add message. */
- MSG_SWAP_INST_REMOVE = 0x0009, /**< Swap inst remove message. */
- MSG_WRT_LAUNCHER_PORT = 0x8001 /**< WRT launcher port. */
-};
-
-/**
- * @struct basic_msg_fmt
- * @brief Basic part of each message.
- */
-struct basic_msg_fmt {
- u32 msg_id; /**< Message ID. */
- u32 len; /**< Message length. */
-} __packed;
-
-static int msg_handler(void __user *msg)
-{
- int ret;
- u32 size;
- enum MSG_ID msg_id;
- struct msg_buf mb;
- void __user *payload;
- struct basic_msg_fmt bmf;
- enum { size_max = 128 * 1024 * 1024 };
-
- ret = copy_from_user(&bmf, (void *)msg, sizeof(bmf));
- if (ret)
- return ret;
-
- size = bmf.len;
- if (size >= size_max) {
- printk(KERN_INFO "%s: too large message, size=%u\n",
- __func__, size);
- return -ENOMEM;
- }
-
- ret = init_mb(&mb, size);
- if (ret)
- return ret;
-
- payload = msg + sizeof(bmf);
- if (size) {
- ret = copy_from_user(mb.begin, (void *)payload, size);
- if (ret)
- goto uninit;
- }
-
- msg_id = bmf.msg_id;
- switch (msg_id) {
- case MSG_KEEP_ALIVE:
- print_parse_debug("MSG_KEEP_ALIVE. size=%d\n", size);
- ret = msg_keep_alive(&mb);
- break;
- case MSG_START:
- print_parse_debug("MSG_START. size=%d\n", size);
- ret = msg_start(&mb);
- break;
- case MSG_STOP:
- print_parse_debug("MSG_STOP. size=%d\n", size);
- ret = msg_stop(&mb);
- break;
- case MSG_CONFIG:
- print_parse_debug("MSG_CONFIG. size=%d\n", size);
- ret = msg_config(&mb);
- break;
- case MSG_SWAP_INST_ADD:
- print_parse_debug("MSG_SWAP_INST_ADD. size=%d\n", size);
- ret = msg_swap_inst_add(&mb);
- break;
- case MSG_SWAP_INST_REMOVE:
- print_parse_debug("MSG_SWAP_INST_REMOVE. size=%d\n", size);
- ret = msg_swap_inst_remove(&mb);
- break;
- case MSG_WRT_LAUNCHER_PORT: {
- /* TODO: discuss wrt-launcher port transfer */
- int port;
- print_parse_debug("MSG_WRT_LAUNCHER_PORT. size=%d\n", size);
- port = get_wrt_launcher_port();
- if (copy_to_user(payload, &port, sizeof(port))) {
- ret = -EIO;
- break;
- }
- ret = port ? 0 : -EINVAL;
- break;
- }
- default:
- print_err("incorrect message ID [%u]. size=%d\n", msg_id, size);
- ret = -EINVAL;
- break;
- }
-
-uninit:
- uninit_mb(&mb);
- return ret;
-}
-
-static int reg_msg_handler(void)
-{
- set_msg_handler(msg_handler);
- return 0;
-}
-
-static void unreg_msg_handler(void)
-{
- set_msg_handler(NULL);
- pfg_put_all();
-}
-
-static int once(void)
-{
- int ret;
-
- ret = once_cmd();
- if (ret)
- return ret;
-
- ret = init_cpu_deps();
- if (ret)
- return ret;
-
- ret = usm_msg_once();
-
- return ret;
-}
-
-SWAP_LIGHT_INIT_MODULE(once, reg_msg_handler, unreg_msg_handler, NULL, NULL);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/**
- * parser/us_inst.c
- * @author Vyacheslav Cherkashin
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * User-space instrumentation controls.
- */
-
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/probes/probes.h>
-
-#include "msg_parser.h"
-#include "us_inst.h"
-#include "usm_msg.h"
-
-
-struct pfg_item {
- struct list_head list;
- struct pf_group *pfg;
-};
-
-
-static LIST_HEAD(pfg_item_list);
-static DEFINE_SPINLOCK(pfg_item_lock);
-
-
-static struct pfg_msg_cb msg_cb = {
- .msg_info = usm_msg_info,
- .msg_status_info = usm_msg_status_info,
- .msg_term = usm_msg_term,
- .msg_map = usm_msg_map,
- .msg_unmap = usm_msg_unmap
-};
-
-static struct pfg_item *pfg_item_create(struct pf_group *pfg)
-{
- int ret;
- struct pfg_item *item;
-
- ret = pfg_msg_cb_set(pfg, &msg_cb);
- if (ret)
- return ERR_PTR(ret);
-
- item = kmalloc(sizeof(*item), GFP_KERNEL);
- if (item == NULL)
- return ERR_PTR(-ENOMEM);
-
- INIT_LIST_HEAD(&item->list);
- item->pfg = pfg;
-
- return item;
-}
-
-static void pfg_item_free(struct pfg_item *item)
-{
- pfg_msg_cb_reset(item->pfg);
- kfree(item);
-}
-
-/* called with pfg_item_lock held */
-static bool pfg_check(struct pf_group *pfg)
-{
- struct pfg_item *item;
-
- list_for_each_entry(item, &pfg_item_list, list) {
- if (item->pfg == pfg)
- return true;
- }
-
- return false;
-}
-
-static int pfg_add(struct pf_group *pfg)
-{
- bool already;
-
- spin_lock(&pfg_item_lock);
- already = pfg_check(pfg);
- spin_unlock(&pfg_item_lock);
-
- if (already) {
- put_pf_group(pfg);
- } else {
- struct pfg_item *item;
-
- item = pfg_item_create(pfg);
- if (IS_ERR(item))
- return PTR_ERR(item);
-
- spin_lock(&pfg_item_lock);
- list_add(&item->list, &pfg_item_list);
- spin_unlock(&pfg_item_lock);
- }
-
- return 0;
-}
-
-void pfg_put_all(void)
-{
- LIST_HEAD(tmp_list);
- struct pfg_item *item, *n;
-
- spin_lock(&pfg_item_lock);
- list_splice_init(&pfg_item_list, &tmp_list);
- spin_unlock(&pfg_item_lock);
-
- list_for_each_entry_safe(item, n, &tmp_list, list) {
- struct pf_group *pfg = item->pfg;
-
- list_del(&item->list);
- pfg_item_free(item);
- put_pf_group(pfg);
- }
-}
-
-static int mod_func_inst(struct func_inst_data *func, struct pf_group *pfg,
- struct dentry *dentry, enum MOD_TYPE mt)
-{
- int ret;
-
- switch (mt) {
- case MT_ADD:
- ret = pf_register_probe(pfg, dentry, func->addr,
- &func->probe_i);
- break;
- case MT_DEL:
- ret = pf_unregister_probe(pfg, dentry, func->addr);
- break;
- default:
- printk(KERN_INFO "ERROR: mod_type=0x%x\n", mt);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int mod_lib_inst(struct lib_inst_data *lib, struct pf_group *pfg,
- enum MOD_TYPE mt)
-{
- int ret = 0, i;
- struct dentry *dentry;
-
- dentry = dentry_by_path(lib->path);
- if (dentry == NULL) {
- printk(KERN_INFO "Cannot get dentry by path %s\n", lib->path);
- return -EINVAL;
- }
-
- for (i = 0; i < lib->cnt_func; ++i) {
- ret = mod_func_inst(lib->func[i], pfg, dentry, mt);
- if (ret) {
- printk(KERN_INFO "Cannot mod func inst, ret = %d\n",
- ret);
- return ret;
- }
- }
-
- return ret;
-}
-
-static int get_pfg_by_app_info(struct app_info_data *app_info,
- struct pf_group **pfg)
-{
- struct dentry *dentry;
-
- dentry = dentry_by_path(app_info->exec_path);
- if (dentry == NULL)
- return -EINVAL;
-
- switch (app_info->app_type) {
- case AT_PID:
- if (app_info->tgid == 0) {
- if (app_info->exec_path[0] == '\0')
- *pfg = get_pf_group_dumb(dentry);
- else
- goto pf_dentry;
- } else
- *pfg = get_pf_group_by_tgid(app_info->tgid, dentry);
- break;
- case AT_TIZEN_WEB_APP:
- *pfg = get_pf_group_by_comm(app_info->app_id, dentry);
- break;
- case AT_TIZEN_NATIVE_APP:
- case AT_COMMON_EXEC:
- pf_dentry:
- *pfg = get_pf_group_by_dentry(dentry, dentry);
- break;
- default:
- printk(KERN_INFO "ERROR: app_type=0x%x\n", app_info->app_type);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int mod_us_app_inst(struct app_inst_data *app_inst, enum MOD_TYPE mt)
-{
- int ret, i;
- struct pf_group *pfg;
- struct dentry *dentry;
-
- ret = get_pfg_by_app_info(app_inst->app_info, &pfg);
- if (ret) {
- printk(KERN_INFO "Cannot get pfg by app info, ret = %d\n", ret);
- return ret;
- }
-
- ret = pfg_add(pfg);
- if (ret) {
- put_pf_group(pfg);
- printk(KERN_INFO "Cannot pfg_add, ret=%d\n", ret);
- return ret;
- }
-
- for (i = 0; i < app_inst->cnt_func; ++i) {
- /* TODO: */
- dentry = dentry_by_path(app_inst->app_info->exec_path);
- if (dentry == NULL) {
- printk(KERN_INFO "Cannot find dentry by path %s\n",
- app_inst->app_info->exec_path);
- return -EINVAL;
- }
-
- ret = mod_func_inst(app_inst->func[i], pfg, dentry, mt);
- if (ret) {
- printk(KERN_INFO "Cannot mod func inst, ret = %d\n",
- ret);
- return ret;
- }
- }
-
- for (i = 0; i < app_inst->cnt_lib; ++i) {
- ret = mod_lib_inst(app_inst->lib[i], pfg, mt);
- if (ret) {
- printk(KERN_INFO "Cannot mod lib inst, ret = %d\n",
- ret);
- return ret;
- }
- }
-
- return 0;
-}
-
-/**
- * @brief Registers probes.
- *
- * @param us_inst Pointer to the target us_inst_data struct.
- * @param mt Modificator, indicates whether we install or remove probes.
- * @return 0 on suceess, error code on error.
- */
-int mod_us_inst(struct us_inst_data *us_inst, enum MOD_TYPE mt)
-{
- u32 i;
- int ret;
-
- for (i = 0; i < us_inst->cnt; ++i) {
- ret = mod_us_app_inst(us_inst->app_inst[i], mt);
- if (ret) {
- printk(KERN_INFO "Cannot mod us app inst, ret = %d\n",
- ret);
- return ret;
- }
- }
-
- return 0;
-}
+++ /dev/null
-/**
- * @file parser/us_inst.h
- * @author Vyacheslav Cherkashin
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * User-space instrumentation controls interface.
- */
-
-
-#ifndef _US_INST_H
-#define _US_INST_H
-
-/**
- * @enum MOD_TYPE
- * @brief Type of mod_us_inst behaviour. */
-enum MOD_TYPE {
- MT_ADD, /**< Add probes. */
- MT_DEL /**< Remove probes. */
-};
-
-struct us_inst_data;
-
-int mod_us_inst(struct us_inst_data *us_inst, enum MOD_TYPE mt);
-void pfg_put_all(void);
-
-#endif /* _US_INST_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/dcache.h>
-#include <linux/fdtable.h>
-#include <writer/swap_msg.h>
-#include <us_manager/sspt/sspt.h> /* ... check_vma() */
-
-
-#define USM_PREFIX KERN_INFO "[USM] "
-
-
-static struct files_struct *(*swap_get_files_struct)(struct task_struct *);
-static void (*swap_put_files_struct)(struct files_struct *fs);
-
-int usm_msg_once(void)
-{
- const char *sym;
-
- sym = "get_files_struct";
- swap_get_files_struct = (void *)swap_ksyms(sym);
- if (swap_get_files_struct == NULL)
- goto not_found;
-
- sym = "put_files_struct";
- swap_put_files_struct = (void *)swap_ksyms(sym);
- if (swap_put_files_struct == NULL)
- goto not_found;
-
- return 0;
-
-not_found:
- printk("ERROR: symbol '%s' not found\n", sym);
- return -ESRCH;
-}
-
-
-
-
-
-struct kmem_info {
- const char *name;
- unsigned long start;
- unsigned long end;
-};
-
-static void kmem_info_fill(struct kmem_info *info, struct mm_struct *mm)
-{
-#if defined(CONFIG_ARM)
- info->name = "[vectors]";
- info->start = CONFIG_VECTORS_BASE;
- info->end = CONFIG_VECTORS_BASE + PAGE_SIZE;
-#elif defined(CONFIG_X86_32)
- unsigned long vdso;
- struct vm_area_struct *vma_vdso;
-
- vdso = (unsigned long)mm->context.vdso;
- vma_vdso = find_vma_intersection(mm, vdso, vdso + 1);
- if (vma_vdso) {
- info->name = "[vdso]";
- info->start = vma_vdso->vm_start;
- info->end = vma_vdso->vm_end;
- } else {
- printk(USM_PREFIX "Cannot get VDSO mapping\n");
-
- info->name = NULL;
- info->start = 0;
- info->end = 0;
- }
-#endif /* CONFIG_arch */
-}
-
-
-static int pack_path(void *data, size_t size, struct file *file)
-{
- enum { TMP_BUF_LEN = 512 };
- char tmp_buf[TMP_BUF_LEN];
- const char NA[] = "N/A";
- const char *filename;
- size_t len = sizeof(NA);
-
- if (file == NULL) {
- filename = NA;
- goto cp2buf;
- }
-
- path_get(&file->f_path);
- filename = d_path(&file->f_path, tmp_buf, TMP_BUF_LEN);
- path_put(&file->f_path);
-
- if (IS_ERR_OR_NULL(filename)) {
- filename = NA;
- goto cp2buf;
- }
-
- len = strlen(filename) + 1;
-
-cp2buf:
- if (size < len)
- return -ENOMEM;
-
- memcpy(data, filename, len);
- return len;
-}
-
-
-
-
-
-/* ============================================================================
- * = MSG_PROCESS_INFO =
- * ============================================================================
- */
-struct proc_info_top {
- u32 pid;
- char comm[0];
-} __packed;
-
-struct proc_info_bottom {
- u32 ppid;
- u64 start_time;
- u64 low_addr;
- u64 high_addr;
- char bin_path[0];
-} __packed;
-
-struct lib_obj {
- u64 low_addr;
- u64 high_addr;
- char lib_path[0];
-} __packed;
-
-static int pack_lib_obj(void *data, size_t size, struct vm_area_struct *vma)
-{
- int ret;
- struct lib_obj *obj = (struct lib_obj *)data;
-
- if (size < sizeof(*obj))
- return -ENOMEM;
-
- obj->low_addr = vma->vm_start;
- obj->high_addr = vma->vm_end;
- size -= sizeof(*obj);
-
- ret = pack_path(obj->lib_path, size, vma->vm_file);
- if (ret < 0)
- return ret;
-
- return ret + sizeof(*obj);
-}
-
-static int pack_shared_kmem(void *data, size_t size, struct mm_struct *mm)
-{
- struct lib_obj *obj = (struct lib_obj *)data;
- struct kmem_info info;
- size_t name_len, obj_size;
-
- if (size < sizeof(*obj))
- return -ENOMEM;
-
- kmem_info_fill(&info, mm);
-
- if (info.name == NULL)
- return 0;
-
- obj->low_addr = (u64)info.start;
- obj->high_addr = (u64)info.end;
-
- name_len = strlen(info.name) + 1;
- obj_size = sizeof(*obj) + name_len;
- if (size < obj_size)
- return -ENOMEM;
-
- memcpy(obj->lib_path, info.name, name_len);
-
- return obj_size;
-}
-
-static int pack_libs(void *data, size_t size, struct mm_struct *mm)
-{
- int ret;
- struct vm_area_struct *vma;
- u32 *lib_cnt = (u32 *)data;
- const size_t old_size = size;
-
- if (size < sizeof(*lib_cnt))
- return -ENOMEM;
-
- /* packing libraries count */
- *lib_cnt = 0;
- data += sizeof(*lib_cnt);
- size -= sizeof(*lib_cnt);
-
- /* packing libraries */
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- if (check_vma(vma)) {
- ret = pack_lib_obj(data, size, vma);
- if (ret < 0)
- return ret;
-
- data += ret;
- size -= ret;
- ++(*lib_cnt);
- }
- }
-
- /* packing shared kernel memory */
- ret = pack_shared_kmem(data, size, mm);
- if (ret < 0)
- return ret;
-
- *lib_cnt += !!ret;
- size -= ret;
-
- return old_size - size;
-}
-
-static struct vm_area_struct *find_vma_exe_by_dentry(struct mm_struct *mm,
- struct dentry *dentry)
-{
- struct vm_area_struct *vma;
-
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- if (vma->vm_file && (vma->vm_flags & VM_EXEC) &&
- (vma->vm_file->f_dentry == dentry))
- goto out;
- }
-
- vma = NULL;
-out:
-
- return vma;
-}
-
-static int pack_proc_info_top(void *data, size_t size,
- struct task_struct *task)
-{
- struct proc_info_top *pit = (struct proc_info_top *)data;
-
- if (size < sizeof(*pit) + sizeof(task->comm))
- return -ENOMEM;
-
- pit->pid = task->tgid;
- get_task_comm(pit->comm, task);
-
- return sizeof(*pit) + strlen(pit->comm) + 1;
-}
-
-static int pack_proc_info_bottom(void *data, size_t size,
- struct task_struct *task,
- struct dentry *dentry)
-{
- struct proc_info_bottom *pib = (struct proc_info_bottom *)data;
- struct vm_area_struct *vma = find_vma_exe_by_dentry(task->mm, dentry);
- struct timespec boot_time;
- struct timespec start_time;
- int ret;
-
- if (size < sizeof(*pib))
- return -ENOMEM;
-
- getboottime(&boot_time);
- start_time = timespec_add(boot_time, task->real_start_time);
-
- pib->ppid = task->real_parent->tgid;
- pib->start_time = swap_msg_spec2time(&start_time);
-
- if (vma) {
- pib->low_addr = vma->vm_start;
- pib->high_addr = vma->vm_end;
- ret = pack_path(pib->bin_path, size, vma->vm_file);
- } else {
- pib->low_addr = 0;
- pib->high_addr = 0;
- ret = pack_path(pib->bin_path, size, NULL);
- }
-
- if (ret < 0)
- return ret;
-
- return sizeof(*pib) + ret;
-}
-
-static int pack_proc_info(void *data, size_t size, struct task_struct *task,
- struct dentry *dentry)
-{
- int ret;
- const size_t old_size = size;
-
- ret = pack_proc_info_top(data, size, task);
- if (ret < 0)
- return ret;
-
- data += ret;
- size -= ret;
-
- ret = pack_proc_info_bottom(data, size, task, dentry);
- if (ret < 0)
- return ret;
-
- data += ret;
- size -= ret;
-
- ret = pack_libs(data, size, task->mm);
- if (ret < 0)
- return ret;
-
- return old_size - size + ret;
-}
-
-/* Called with down\up\_read(&task->mm->mmap_sem). */
-void usm_msg_info(struct task_struct *task, struct dentry *dentry)
-{
- int ret;
- struct swap_msg *m;
- void *p;
- size_t size;
-
- m = swap_msg_get(MSG_PROC_INFO);
- p = swap_msg_payload(m);
- size = swap_msg_size(m);
-
- ret = pack_proc_info(p, size, task, dentry);
- if (ret < 0) {
- printk(USM_PREFIX "ERROR: message process info packing, "
- "ret=%d\n", ret);
- goto put_msg;
- }
-
- swap_msg_flush(m, ret);
-
-put_msg:
- swap_msg_put(m);
-}
-
-
-
-
-
-/* ============================================================================
- * = MSG_TERMINATE =
- * ============================================================================
- */
-struct proc_terminate {
- u32 pid;
-} __packed;
-
-void usm_msg_term(struct task_struct *task)
-{
- struct swap_msg *m;
- struct proc_terminate *term;
-
- m = swap_msg_get(MSG_TERMINATE);
-
- term = swap_msg_payload(m);
- term->pid = task->pid;
-
- swap_msg_flush(m, sizeof(*term));
- swap_msg_put(m);
-}
-
-
-
-
-
-/* ============================================================================
- * = MSG_PROCESS_MAP =
- * ============================================================================
- */
-struct proc_map {
- u32 pid;
- u64 low_addr;
- u64 high_addr;
- char bin_path[0];
-} __packed;
-
-static int pack_proc_map(void *data, size_t size, struct vm_area_struct *vma)
-{
- struct proc_map *map = (struct proc_map *)data;
- int ret;
-
- map->pid = current->tgid;
- map->low_addr = vma->vm_start;
- map->high_addr = vma->vm_end;
-
- ret = pack_path(map->bin_path, size - sizeof(*map), vma->vm_file);
- if (ret < 0)
- return ret;
-
- return ret + sizeof(*map);
-}
-
-void usm_msg_map(struct vm_area_struct *vma)
-{
- int ret;
- struct swap_msg *m;
- void *p;
- size_t size;
-
- m = swap_msg_get(MSG_PROC_MAP);
- p = swap_msg_payload(m);
- size = swap_msg_size(m);
-
- ret = pack_proc_map(p, size, vma);
- if (ret < 0) {
- printk(USM_PREFIX "ERROR: message process mapping packing, "
- "ret=%d\n", ret);
- goto put_msg;
- }
-
- swap_msg_flush(m, ret);
-
-put_msg:
- swap_msg_put(m);
-}
-
-
-
-
-
-/* ============================================================================
- * = MSG_PROCESS_UNMAP =
- * ============================================================================
- */
-struct proc_unmap {
- u32 pid;
- u64 low_addr;
- u64 high_addr;
-} __packed;
-
-void usm_msg_unmap(unsigned long start, unsigned long end)
-{
- struct swap_msg *m;
- struct proc_unmap *unmap;
-
- m = swap_msg_get(MSG_PROC_UNMAP);
-
- unmap = swap_msg_payload(m);
- unmap->pid = current->tgid;
- unmap->low_addr = (u64)start;
- unmap->high_addr = (u64)end;
-
- swap_msg_flush(m, sizeof(*unmap));
- swap_msg_put(m);
-}
-
-
-
-
-
-/* ============================================================================
- * = MSG_PROCESS_COMM =
- * ============================================================================
- */
-struct proc_comm {
- u32 pid;
- char comm[0];
-} __packed;
-
-void usm_msg_comm(struct task_struct *task)
-{
- struct swap_msg *m;
- struct proc_comm *c;
-
- m = swap_msg_get(MSG_PROC_COMM);
-
- c = swap_msg_payload(m);
- c->pid = task->tgid;
- get_task_comm(c->comm, task);
-
- swap_msg_flush(m, sizeof(*c) + strlen(c->comm) + 1);
- swap_msg_put(m);
-}
-
-
-
-
-
-/* ============================================================================
- * = MSG_PROCESS_STATUS_INFO =
- * ============================================================================
- */
-struct ofile {
- u32 fd;
- u64 size;
- char path[0];
-} __packed;
-
-static int pack_ofile(void *data, size_t size, int fd, struct file *file,
- loff_t fsize)
-{
- int ret;
- struct ofile *ofile;
-
- if (size < sizeof(*ofile))
- return -ENOMEM;
-
- ofile = (struct ofile *)data;
- ofile->fd = (u32)fd;
- ofile->size = (u64)fsize;
-
- ret = pack_path(ofile->path, size - sizeof(*ofile), file);
- if (ret < 0)
- return ret;
-
- return sizeof(*ofile) + ret;
-}
-
-static int pack_status_info(void *data, size_t size, struct task_struct *task)
-{
- int ret, fd;
- u32 *file_cnt;
- struct files_struct *files;
- const size_t old_size = size;
-
- files = swap_get_files_struct(task);
- if (files == NULL)
- return -EIO;
-
- /* pack pid */
- *((u32 *)data) = (u32)task->tgid;
- data += 4;
- size -= 4;
-
- /* pack file count */
- file_cnt = (u32 *)data;
- *file_cnt = 0;
- data += 4;
- size -= 4;
-
- /* pack file list */
- rcu_read_lock();
- for (fd = 0; fd < files_fdtable(files)->max_fds; ++fd) {
- struct file *file;
- struct inode *inode;
- loff_t fsize;
-
- file = fcheck_files(files, fd);
- if (file == NULL)
- continue;
-
- inode = file->f_path.dentry->d_inode;
- /* check inode and if it is a regular file */
- if (inode == NULL || !S_ISREG(inode->i_mode))
- continue;
-
- fsize = inode->i_size;
- rcu_read_unlock();
-
- ret = pack_ofile(data, size, fd, file, fsize);
- if (ret < 0)
- goto put_fstruct;
-
- data += ret;
- size -= ret;
- ++(*file_cnt);
-
- rcu_read_lock();
- }
- rcu_read_unlock();
- ret = old_size - size;
-
-put_fstruct:
- swap_put_files_struct(files);
- return ret;
-}
-
-void usm_msg_status_info(struct task_struct *task)
-{
- int ret;
- void *data;
- size_t size;
- struct swap_msg *m;
-
- m = swap_msg_get(MSG_PROCESS_STATUS_INFO);
-
- data = swap_msg_payload(m);
- size = swap_msg_size(m);
- ret = pack_status_info(data, size, task);
- if (ret < 0) {
- printk(USM_PREFIX "ERROR: MSG_PROCESS_STATUS_INFO "
- "packing, ret=%d\n", ret);
- goto put_msg;
- }
-
- swap_msg_flush(m, ret);
-
-put_msg:
- swap_msg_put(m);
-}
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _USM_MSG_H
-#define _USM_MSG_H
-
-
-struct dentry;
-struct task_struct;
-struct vm_area_struct;
-
-int usm_msg_once(void);
-
-void usm_msg_info(struct task_struct *task, struct dentry *dentry);
-void usm_msg_term(struct task_struct *task);
-void usm_msg_map(struct vm_area_struct *vma);
-void usm_msg_unmap(unsigned long start, unsigned long end);
-void usm_msg_comm(struct task_struct *task);
-void usm_msg_status_info(struct task_struct *task);
-
-
-#endif /* _USM_MSG_H */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_preload.o
-swap_preload-y := preload_module.o \
- preload_debugfs.o \
- preload_storage.o \
- preload_probe.o \
- preload_control.o \
- preload_threads.o \
- preload_pd.o
+++ /dev/null
-#ifndef __PRELOAD__
-#define __PRELOAD__
-
-#define PRELOAD_PREFIX "SWAP_PRELOAD: "
-#define PRELOAD_MAX_ATTEMPTS 10
-#define PRELOAD_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
-
-#endif /* __PRELOAD__ */
+++ /dev/null
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/limits.h>
-
-#include <us_manager/sspt/ip.h>
-
-#include "preload.h"
-
-#include "preload_control.h"
-#include "preload_probe.h"
-#include "preload_module.h"
-
-
-#define DEFAULT_SLOTS_COUNT 5
-#define DEFAULT_SLOTS_STEP 2
-
-struct bin_desc {
- struct dentry *dentry;
- char *filename;
-};
-
-static struct bin_desc *target_binaries = NULL;
-static unsigned int target_binaries_cnt = 0;
-static unsigned int target_binaries_slots = 0;
-
-static DEFINE_MUTEX(__target_binaries_mutex);
-
-
-static inline void __target_binaries_lock(void)
-{
- mutex_lock(&__target_binaries_mutex);
-}
-
-static inline void __target_binaries_unlock(void)
-{
- mutex_unlock(&__target_binaries_mutex);
-}
-
-static inline struct task_struct *__get_task_struct(void)
-{
- return current;
-}
-
-static int __alloc_target_binaries_no_lock(unsigned int cnt)
-{
- target_binaries = kmalloc(sizeof(*target_binaries) * cnt, GFP_KERNEL);
- if (target_binaries == NULL)
- return -ENOMEM;
-
- target_binaries_slots = cnt;
-
- return 0;
-}
-
-static int __alloc_target_binaries(unsigned int cnt)
-{
- int ret;
-
- __target_binaries_lock();
- ret = __alloc_target_binaries_no_lock(cnt);
- __target_binaries_unlock();
-
- return ret;
-}
-
-static void __free_target_binaries(void)
-{
- int i;
-
- __target_binaries_lock();
-
- for (i = 0; i < target_binaries_cnt; i++) {
- put_dentry(target_binaries[i].dentry);
- kfree(target_binaries[i].filename);
- }
-
- kfree(target_binaries);
- target_binaries_cnt = 0;
- target_binaries_slots = 0;
-
- __target_binaries_unlock();
-}
-
-static int __grow_target_binaries(void)
-{
- struct bin_desc *tmp = target_binaries;
- int i, ret;
-
- __target_binaries_lock();
-
- ret = __alloc_target_binaries_no_lock(target_binaries_slots + DEFAULT_SLOTS_STEP);
- if (ret != 0)
- return ret;
-
- target_binaries_slots += DEFAULT_SLOTS_STEP;
-
- for (i = 0; i < target_binaries_cnt; i++) {
- target_binaries[i].dentry = tmp[i].dentry;
- target_binaries[i].filename = tmp[i].filename;
- }
-
- __target_binaries_unlock();
-
- kfree(tmp);
-
- return 0;
-}
-
-static bool __check_dentry_already_exist(struct dentry *dentry)
-{
- int i;
- bool ret = false;
-
- __target_binaries_lock();
-
- for (i = 0; i < target_binaries_cnt; i++) {
- if (target_binaries[i].dentry == dentry) {
- ret = true;
- goto check_dentry_unlock;
- }
- }
-
-check_dentry_unlock:
- __target_binaries_unlock();
-
- return ret;
-}
-
-static int __add_target_binary(struct dentry *dentry, char *filename)
-{
- int ret;
- size_t len;
-
- if (__check_dentry_already_exist(dentry)) {
- printk(PRELOAD_PREFIX "Binary already exist\n");
- return EALREADY;
- }
-
-
- if (target_binaries_slots == target_binaries_cnt) {
- ret = __grow_target_binaries();
- if (ret != 0)
- return ret;
- }
-
- /* Filename should be < PATH_MAX */
- len = strnlen(filename, PATH_MAX);
- if (len == PATH_MAX)
- return -EINVAL;
-
- __target_binaries_lock();
-
- target_binaries[target_binaries_cnt].dentry = dentry;
- target_binaries[target_binaries_cnt].filename = kmalloc(len + 1, GFP_KERNEL);
- memcpy(target_binaries[target_binaries_cnt].filename, filename, len + 1);
- ++target_binaries_cnt;
-
- __target_binaries_unlock();
-
- return 0;
-}
-
-static char *__get_binary_name(struct bin_desc *bin)
-{
- return bin->filename;
-}
-
-static struct dentry *__get_caller_dentry(struct task_struct *task,
- unsigned long caller)
-{
- struct vm_area_struct *vma = NULL;
-
- if (unlikely(task->mm == NULL))
- goto get_caller_dentry_fail;
-
- vma = find_vma_intersection(task->mm, caller, caller + 1);
- if (unlikely(vma == NULL || vma->vm_file == NULL))
- goto get_caller_dentry_fail;
-
- return vma->vm_file->f_dentry;
-
-get_caller_dentry_fail:
-
- return NULL;
-}
-
-static bool __check_if_instrumented(struct task_struct *task,
- struct dentry *dentry)
-{
- int i;
-
- for (i = 0; i < target_binaries_cnt; i++)
- if (target_binaries[i].dentry == dentry)
- return true;
-
- return false;
-}
-
-static bool __is_instrumented(void *caller)
-{
- struct task_struct *task = __get_task_struct();
- struct dentry *caller_dentry = __get_caller_dentry(task,
- (unsigned long) caller);
-
- if (caller_dentry == NULL)
- return false;
-
- return __check_if_instrumented(task, caller_dentry);
-}
-
-
-/* Called only form handlers. If we're there, then it is instrumented. */
-enum preload_call_type preload_control_call_type_always_inst(void *caller)
-{
- if (__is_instrumented(caller))
- return INTERNAL_CALL;
-
- return EXTERNAL_CALL;
-
-}
-
-enum preload_call_type preload_control_call_type(struct us_ip *ip, void *caller)
-{
- if (__is_instrumented(caller))
- return INTERNAL_CALL;
-
- if (ip->info->pl_i.flags & SWAP_PRELOAD_ALWAYS_RUN)
- return EXTERNAL_CALL;
-
- return NOT_INSTRUMENTED;
-}
-
-int preload_control_add_instrumented_binary(char *filename)
-{
- struct dentry *dentry = get_dentry(filename);
- int res = 0;
-
- if (dentry == NULL)
- return -EINVAL;
-
- res = __add_target_binary(dentry, filename);
- if (res != 0)
- put_dentry(dentry);
-
- return res > 0 ? 0 : res;
-}
-
-int preload_control_clean_instrumented_bins(void)
-{
- __free_target_binaries();
- return __alloc_target_binaries(DEFAULT_SLOTS_COUNT);
-}
-
-unsigned int preload_control_get_bin_names(char ***filenames_p)
-{
- int i;
- unsigned int ret = 0;
-
- if (target_binaries_cnt == 0)
- return 0;
-
- __target_binaries_lock();
-
- *filenames_p = kmalloc(sizeof(**filenames_p) * target_binaries_cnt,
- GFP_KERNEL);
- if (*filenames_p == NULL)
- goto get_binaries_names_out;
-
- for (i = 0; i < target_binaries_cnt; i++)
- (*filenames_p)[i] = __get_binary_name(&target_binaries[i]);
-
- ret = target_binaries_cnt;
-
-get_binaries_names_out:
- __target_binaries_unlock();
-
- return ret;
-}
-
-void preload_control_release_bin_names(char ***filenames_p)
-{
- kfree(*filenames_p);
-}
-
-int preload_control_init(void)
-{
- return __alloc_target_binaries(DEFAULT_SLOTS_COUNT);
-}
-
-void preload_control_exit(void)
-{
- __free_target_binaries();
-}
-
-#undef DEFAULT_SLOTS_STEP
-#undef DEFAULT_SLOTS_COUNT
+++ /dev/null
-#ifndef __PRELOAD_CONTROL_H__
-#define __PRELOAD_CONTROL_H__
-
-enum preload_call_type {
- NOT_INSTRUMENTED,
- EXTERNAL_CALL,
- INTERNAL_CALL
-};
-
-int preload_control_init(void);
-void preload_control_exit(void);
-
-enum preload_call_type preload_control_call_type_always_inst(void *caller);
-enum preload_call_type preload_control_call_type(struct us_ip *ip, void *caller);
-int preload_control_add_instrumented_binary(char *filename);
-int preload_control_clean_instrumented_bins(void);
-
-unsigned int preload_control_get_bin_names(char ***filenames_p);
-void preload_control_release_bin_names(char ***filenames_p);
-
-#endif /* __PRELOAD_CONTROL_H__ */
+++ /dev/null
-#include <linux/kernel.h>
-#include <linux/debugfs.h>
-#include <linux/err.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/limits.h>
-#include <asm/uaccess.h>
-#include <master/swap_debugfs.h>
-#include "preload.h"
-#include "preload_debugfs.h"
-#include "preload_module.h"
-#include "preload_control.h"
-#include "preload_storage.h"
-
-static const char PRELOAD_FOLDER[] = "preload";
-static const char PRELOAD_LOADER[] = "loader";
-static const char PRELOAD_LOADER_OFFSET[] = "loader_offset";
-static const char PRELOAD_LOADER_PATH[] = "loader_path";
-static const char PRELOAD_BINARIES[] = "target_binaries";
-static const char PRELOAD_BINARIES_LIST[] = "bins_list";
-static const char PRELOAD_BINARIES_ADD[] = "bins_add";
-static const char PRELOAD_BINARIES_REMOVE[] = "bins_remove";
-static const char PRELOAD_CALLER[] = "caller";
-static const char PRELOAD_HANDLERS_PATH[] = "handlers_path";
-static const char PRELOAD_LINKER_DATA[] = "linker";
-static const char PRELOAD_LINKER_PATH[] = "linker_path";
-static const char PRELOAD_LINKER_R_DEBUG_OFFSET[] = "r_debug_offset";
-
-struct loader_info {
- char *path;
- unsigned long offset;
- struct dentry *dentry;
-};
-
-static struct dentry *preload_root;
-static struct loader_info __loader_info;
-
-static unsigned long r_debug_offset = 0;
-static DEFINE_SPINLOCK(__dentry_lock);
-
-static inline void dentry_lock(void)
-{
- spin_lock(&__dentry_lock);
-}
-
-static inline void dentry_unlock(void)
-{
- spin_unlock(&__dentry_lock);
-}
-
-
-static void set_loader_file(char *path)
-{
- __loader_info.path = path;
- dentry_lock();
- __loader_info.dentry = get_dentry(__loader_info.path);
- dentry_unlock();
-}
-
-struct dentry *preload_debugfs_get_loader_dentry(void)
-{
- struct dentry *dentry;
-
- dentry_lock();
- dentry = __loader_info.dentry;
- dentry_unlock();
-
- return dentry;
-}
-
-unsigned long preload_debugfs_get_loader_offset(void)
-{
- /* TODO Think about sync */
- return __loader_info.offset;
-}
-
-static void clean_loader_info(void)
-{
- if (__loader_info.path != NULL)
- kfree(__loader_info.path);
- __loader_info.path = NULL;
-
- dentry_lock();
- if (__loader_info.dentry != NULL)
- put_dentry(__loader_info.dentry);
-
- __loader_info.dentry = NULL;
- __loader_info.offset = 0;
-
- dentry_unlock();
-}
-
-struct dentry *debugfs_create_ptr(const char *name, mode_t mode,
- struct dentry *parent,
- unsigned long *value)
-{
- struct dentry *dentry;
-
-#if BITS_PER_LONG == 32
- dentry = debugfs_create_x32(name, mode, parent, (u32 *)value);
-#elif BITS_PER_LONG == 64
- dentry = debugfs_create_x64(name, mode, parent, (u64 *)value);
-#else
-#error Unsupported BITS_PER_LONG value
-#endif
-
- return dentry;
-}
-
-
-/* ===========================================================================
- * = LOADER PATH =
- * ===========================================================================
- */
-
-static ssize_t loader_path_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
-{
- ssize_t ret;
- char *path;
-
- if (preload_module_is_running())
- return -EBUSY;
-
- clean_loader_info();
-
- path = kmalloc(len, GFP_KERNEL);
- if (path == NULL) {
- return -ENOMEM;
- }
-
- if (copy_from_user(path, buf, len)) {
- ret = -EINVAL;
- goto err;
- }
-
- path[len - 1] = '\0';
- set_loader_file(path);
- ret = len;
-
- return ret;
-err:
- kfree(path);
- return ret;
-}
-
-
-static const struct file_operations loader_path_file_ops = {
- .owner = THIS_MODULE,
- .write = loader_path_write,
-};
-
-
-/* ===========================================================================
- * = BIN PATH =
- * ===========================================================================
- */
-
-static ssize_t bin_add_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
-{
- ssize_t ret;
- char *path;
-
- path = kmalloc(len, GFP_KERNEL);
- if (path == NULL) {
- ret = -ENOMEM;
- goto bin_add_write_out;
- }
-
- if (copy_from_user(path, buf, len)) {
- ret = -EINVAL;
- goto bin_add_write_out;
- }
-
- path[len - 1] = '\0';
-
- if (preload_control_add_instrumented_binary(path) != 0) {
- printk(PRELOAD_PREFIX "Cannot add binary %s\n", path);
- ret = -EINVAL;
- goto bin_add_write_out;
- }
-
- ret = len;
-
-bin_add_write_out:
- kfree(path);
-
- return ret;
-}
-
-static ssize_t bin_remove_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
-{
- ssize_t ret;
-
- ret = preload_control_clean_instrumented_bins();
- if (ret != 0) {
- printk(PRELOAD_PREFIX "Error during clean!\n");
- ret = -EINVAL;
- goto bin_remove_write_out;
- }
-
- ret = len;
-
-bin_remove_write_out:
- return ret;
-}
-
-static ssize_t bin_list_read(struct file *file, char __user *usr_buf,
- size_t count, loff_t *ppos)
-{
- unsigned int i;
- unsigned int files_cnt = 0;
- ssize_t len = 0, tmp, ret = 0;
- char **filenames = NULL;
- char *buf = NULL;
- char *ptr = NULL;
-
- files_cnt = preload_control_get_bin_names(&filenames);
-
- if (files_cnt == 0) {
- printk(PRELOAD_PREFIX "Cannot read binaries names!\n");
- ret = 0;
- goto bin_list_read_out;
- }
-
- for (i = 0; i < files_cnt; i++)
- len += strlen(filenames[i]);
-
- buf = kmalloc(len + files_cnt, GFP_KERNEL);
- if (buf == NULL) {
- ret = 0;
- goto bin_list_read_fail;
- }
-
- ptr = buf;
-
- for (i = 0; i < files_cnt; i++) {
- tmp = strlen(filenames[i]);
- memcpy(ptr, filenames[i], tmp);
- ptr += tmp;
- *ptr = '\n';
- ptr += 1;
- }
-
- preload_control_release_bin_names(&filenames);
-
- return simple_read_from_buffer(usr_buf, count, ppos, buf, len);
-
-bin_list_read_fail:
- preload_control_release_bin_names(&filenames);
-
-bin_list_read_out:
- return ret;
-}
-
-static const struct file_operations bin_list_file_ops = {
- .owner = THIS_MODULE,
- .read = bin_list_read
-};
-
-static const struct file_operations bin_add_file_ops = {
- .owner = THIS_MODULE,
- .write = bin_add_write,
-};
-
-static const struct file_operations bin_remove_file_ops = {
- .owner = THIS_MODULE,
- .write = bin_remove_write,
-};
-
-
-/* ===========================================================================
- * = LINKER PATH =
- * ===========================================================================
- */
-
-
-static ssize_t linker_path_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
-{
- ssize_t ret;
- char *path;
-
- path = kmalloc(len, GFP_KERNEL);
- if (path == NULL) {
- ret = -ENOMEM;
- goto linker_path_write_out;
- }
-
- if (copy_from_user(path, buf, len)) {
- ret = -EINVAL;
- goto linker_path_write_out;
- }
-
- path[len - 1] = '\0';
-
- if (preload_storage_set_linker_info(path) != 0) {
- printk(PRELOAD_PREFIX "Cannot set linker path %s\n", path);
- ret = -EINVAL;
- goto linker_path_write_out;
- }
-
- ret = len;
-
-linker_path_write_out:
- kfree(path);
-
- return ret;
-}
-
-static const struct file_operations linker_path_file_ops = {
- .owner = THIS_MODULE,
- .write = linker_path_write,
-};
-
-
-/* ===========================================================================
- * = HANDLERS PATH =
- * ===========================================================================
- */
-
-
-static ssize_t handlers_path_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
-{
- ssize_t ret;
- char *path;
-
- path = kmalloc(len, GFP_KERNEL);
- if (path == NULL) {
- ret = -ENOMEM;
- goto handlers_path_write_out;
- }
-
- if (copy_from_user(path, buf, len)) {
- ret = -EINVAL;
- goto handlers_path_write_out;
- }
-
- path[len - 1] = '\0';
-
- if (preload_storage_set_handlers_info(path) != 0) {
- printk(PRELOAD_PREFIX "Cannot set handler path %s\n", path);
- ret = -EINVAL;
- goto handlers_path_write_out;
- }
-
- ret = len;
-
-handlers_path_write_out:
- kfree(path);
-
- return ret;
-}
-
-static const struct file_operations handlers_path_file_ops = {
- .owner = THIS_MODULE,
- .write = handlers_path_write,
-};
-
-
-
-
-unsigned long preload_debugfs_r_debug_offset(void)
-{
- return r_debug_offset;
-}
-
-int preload_debugfs_init(void)
-{
- struct dentry *swap_dentry, *root, *loader, *open_p, *lib_path,
- *bin_path, *bin_list, *bin_add, *bin_remove,
- *linker_dir, *linker_path, *linker_offset, *handlers_path;
- int ret;
-
- ret = -ENODEV;
- if (!debugfs_initialized())
- goto fail;
-
- ret = -ENOENT;
- swap_dentry = swap_debugfs_getdir();
- if (!swap_dentry)
- goto fail;
-
- ret = -ENOMEM;
- root = debugfs_create_dir(PRELOAD_FOLDER, swap_dentry);
- if (IS_ERR_OR_NULL(root))
- goto fail;
-
- preload_root = root;
-
- loader = debugfs_create_dir(PRELOAD_LOADER, root);
- if (IS_ERR_OR_NULL(root)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- open_p = debugfs_create_ptr(PRELOAD_LOADER_OFFSET, PRELOAD_DEFAULT_PERMS,
- loader, &__loader_info.offset);
- if (IS_ERR_OR_NULL(open_p)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- lib_path = debugfs_create_file(PRELOAD_LOADER_PATH, PRELOAD_DEFAULT_PERMS,
- loader, NULL, &loader_path_file_ops);
- if (IS_ERR_OR_NULL(lib_path)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- bin_path = debugfs_create_dir(PRELOAD_BINARIES, root);
- if (IS_ERR_OR_NULL(bin_path)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- bin_list = debugfs_create_file(PRELOAD_BINARIES_LIST, PRELOAD_DEFAULT_PERMS,
- bin_path, NULL, &bin_list_file_ops);
- if (IS_ERR_OR_NULL(bin_list)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- bin_add = debugfs_create_file(PRELOAD_BINARIES_ADD, PRELOAD_DEFAULT_PERMS,
- bin_path, NULL, &bin_add_file_ops);
- if (IS_ERR_OR_NULL(bin_add)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- bin_remove = debugfs_create_file(PRELOAD_BINARIES_REMOVE,
- PRELOAD_DEFAULT_PERMS, bin_path, NULL,
- &bin_remove_file_ops);
- if (IS_ERR_OR_NULL(bin_remove)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- linker_dir = debugfs_create_dir(PRELOAD_LINKER_DATA, root);
- if (IS_ERR_OR_NULL(linker_dir)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- linker_path = debugfs_create_file(PRELOAD_LINKER_PATH,
- PRELOAD_DEFAULT_PERMS, linker_dir, NULL,
- &linker_path_file_ops);
- if (IS_ERR_OR_NULL(linker_path)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- linker_offset = debugfs_create_ptr(PRELOAD_LINKER_R_DEBUG_OFFSET,
- PRELOAD_DEFAULT_PERMS, linker_dir,
- &r_debug_offset);
- if (IS_ERR_OR_NULL(linker_offset)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- handlers_path = debugfs_create_file(PRELOAD_HANDLERS_PATH,
- PRELOAD_DEFAULT_PERMS, root, NULL,
- &handlers_path_file_ops);
- if (IS_ERR_OR_NULL(handlers_path)) {
- ret = -ENOMEM;
- goto remove;
- }
-
- return 0;
-
-remove:
-
- debugfs_remove_recursive(root);
-
-fail:
- printk(PRELOAD_PREFIX "Debugfs initialization failure: %d\n", ret);
-
- return ret;
-}
-
-void preload_debugfs_exit(void)
-{
- if (preload_root)
- debugfs_remove_recursive(preload_root);
- preload_root = NULL;
-
- preload_module_set_not_ready();
- clean_loader_info();
-}
+++ /dev/null
-#ifndef __PRELOAD_DEBUGFS_H__
-#define __PRELOAD_DEBUGFS_H__
-
-struct dentry;
-
-int preload_debugfs_init(void);
-void preload_debugfs_exit(void);
-
-struct dentry *preload_debugfs_get_loader_dentry(void);
-unsigned long preload_debugfs_get_loader_offset(void);
-
-struct dentry *preload_debugfs_create_new_thread(unsigned long tid);
-
-unsigned long preload_debugfs_r_debug_offset(void);
-
-#endif /* __PRELOAD_DEBUGFS_H__ */
+++ /dev/null
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/dcache.h>
-#include <linux/namei.h>
-#include <linux/slab.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/err.h>
-#include <linux/types.h>
-#include <linux/uaccess.h>
-#include <kprobe/swap_kprobes.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <us_manager/us_manager_common.h>
-#include <us_manager/sspt/sspt_page.h>
-#include <us_manager/sspt/sspt_file.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/sspt/ip.h>
-#include <us_manager/callbacks.h>
-#include <writer/kernel_operations.h>
-#include <master/swap_initializer.h>
-#include <writer/swap_msg.h>
-#include <task_data/task_data.h>
-#include "preload.h"
-#include "preload_probe.h"
-#include "preload_debugfs.h"
-#include "preload_module.h"
-#include "preload_storage.h"
-#include "preload_control.h"
-#include "preload_threads.h"
-#include "preload_pd.h"
-
-#define page_to_proc(page) ((page)->file->proc)
-#define page_to_dentry(page) ((page)->file->dentry)
-#define ip_to_proc(ip) page_to_proc((ip)->page)
-
-struct us_priv {
- struct pt_regs regs;
- unsigned long arg0;
- unsigned long arg1;
- unsigned long raddr;
- unsigned long origin;
-};
-
-static atomic_t dentry_balance = ATOMIC_INIT(0);
-
-enum preload_status_t {
- SWAP_PRELOAD_NOT_READY = 0,
- SWAP_PRELOAD_READY = 1,
- SWAP_PRELOAD_RUNNING = 2
-};
-
-enum {
- /* task preload flags */
- HANDLER_RUNNING = 0x1
-};
-
-static enum preload_status_t __preload_status = SWAP_PRELOAD_NOT_READY;
-
-static int __preload_cbs_start_h = -1;
-static int __preload_cbs_stop_h = -1;
-
-static inline struct process_data *__get_process_data(struct uretprobe *rp)
-{
- struct us_ip *ip = to_us_ip(rp);
- struct sspt_proc *proc = ip_to_proc(ip);
-
- return preload_pd_get(proc);
-}
-
-static struct dentry *__get_dentry(struct dentry *dentry)
-{
- atomic_inc(&dentry_balance);
- return dget(dentry);
-}
-
-
-
-bool preload_module_is_running(void)
-{
- if (__preload_status == SWAP_PRELOAD_RUNNING)
- return true;
-
- return false;
-}
-
-bool preload_module_is_ready(void)
-{
- if (__preload_status == SWAP_PRELOAD_READY)
- return true;
-
- return false;
-}
-
-bool preload_module_is_not_ready(void)
-{
- if (__preload_status == SWAP_PRELOAD_NOT_READY)
- return true;
-
- return false;
-}
-
-void preload_module_set_ready(void)
-{
- __preload_status = SWAP_PRELOAD_READY;
-}
-
-void preload_module_set_running(void)
-{
- __preload_status = SWAP_PRELOAD_RUNNING;
-}
-
-void preload_module_set_not_ready(void)
-{
- __preload_status = SWAP_PRELOAD_NOT_READY;
-}
-
-struct dentry *get_dentry(const char *filepath)
-{
- struct path path;
- struct dentry *dentry = NULL;
-
- if (kern_path(filepath, LOOKUP_FOLLOW, &path) == 0) {
- dentry = __get_dentry(path.dentry);
- path_put(&path);
- }
-
- return dentry;
-}
-
-void put_dentry(struct dentry *dentry)
-{
- atomic_dec(&dentry_balance);
- dput(dentry);
-}
-
-static inline void __prepare_ujump(struct uretprobe_instance *ri,
- struct pt_regs *regs,
- unsigned long vaddr)
-{
- ri->rp->up.kp.ss_addr[smp_processor_id()] = (kprobe_opcode_t *)vaddr;
-
-#ifdef CONFIG_ARM
- if (thumb_mode(regs)) {
- regs->ARM_cpsr &= ~PSR_T_BIT;
- ri->preload_thumb = 1;
- }
-#endif /* CONFIG_ARM */
-}
-
-static inline int __push(struct pt_regs *regs, void *buf, size_t len)
-{
- unsigned long sp = swap_get_stack_ptr(regs) - len;
-
- sp = PTR_ALIGN(sp, sizeof(unsigned long));
- if (copy_to_user((void __user *)sp, buf, len))
- return -EIO;
- swap_set_stack_ptr(regs, sp);
-
- return 0;
-}
-
-static inline void __save_uregs(struct uretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct us_priv *priv = (struct us_priv *)ri->data;
-
- memcpy(ri->data, regs, sizeof(*regs));
- priv->arg0 = swap_get_arg(regs, 0);
- priv->arg1 = swap_get_arg(regs, 1);
- priv->raddr = swap_get_ret_addr(regs);
-}
-
-static inline void __restore_uregs(struct uretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct us_priv *priv = (struct us_priv *)ri->data;
-
- memcpy(regs, ri->data, sizeof(*regs));
- swap_set_arg(regs, 0, priv->arg0);
- swap_set_arg(regs, 1, priv->arg1);
- swap_set_ret_addr(regs, priv->raddr);
-#ifndef CONFIG_ARM
- /* need to do it only on x86 */
- regs->EREG(ip) -= 1;
-#endif /* !CONFIG_ARM */
- /* we have just restored the registers => no need to do it in
- * trampoline_uprobe_handler */
- ri->ret_addr = NULL;
-}
-
-static inline void print_regs(const char *prefix, struct pt_regs *regs,
- struct uretprobe_instance *ri)
-{
-#ifdef CONFIG_ARM
- printk(PRELOAD_PREFIX "%s[%d/%d] (%d) %s addr(%08lx), "
- "r0(%08lx), r1(%08lx), r2(%08lx), r3(%08lx), "
- "r4(%08lx), r5(%08lx), r6(%08lx), r7(%08lx), "
- "sp(%08lx), lr(%08lx), pc(%08lx)\n",
- current->comm, current->tgid, current->pid,
- (int)preload_pd_get_state(__get_process_data(ri->rp)),
- prefix, (unsigned long)ri->rp->up.kp.addr,
- regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3,
- regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7,
- regs->ARM_sp, regs->ARM_lr, regs->ARM_pc);
-#else /* !CONFIG_ARM */
- printk(PRELOAD_PREFIX "%s[%d/%d] (%d) %s addr(%08lx), "
- "ip(%08lx), arg0(%08lx), arg1(%08lx), raddr(%08lx)\n",
- current->comm, current->tgid, current->pid,
- (int)preload_pd_get_state(__get_process_data(ri->rp)),
- prefix, (unsigned long)ri->rp->up.kp.addr,
- regs->EREG(ip), swap_get_arg(regs, 0), swap_get_arg(regs, 1),
- swap_get_ret_addr(regs));
-#endif /* CONFIG_ARM */
-}
-
-static inline unsigned long __get_r_debug_off(struct vm_area_struct *linker_vma)
-{
- unsigned long start_addr;
- unsigned long offset = preload_debugfs_r_debug_offset();
-
- if (linker_vma == NULL)
- return 0;
-
- start_addr = linker_vma->vm_start;
-
- return (offset ? start_addr + offset : 0);
-}
-
-static struct vm_area_struct *__get_linker_vma(struct task_struct *task)
-{
- struct vm_area_struct *vma = NULL;
- struct bin_info *ld_info;
-
- ld_info = preload_storage_get_linker_info();
- if (ld_info == NULL) {
- printk(PRELOAD_PREFIX "Cannot get linker info [%u %u %s]!\n",
- task->tgid, task->pid, task->comm);
- return NULL;
- }
-
- for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
- if (vma->vm_file && vma->vm_flags & VM_EXEC
- && vma->vm_file->f_dentry == ld_info->dentry) {
- preload_storage_put_linker_info(ld_info);
- return vma;
- }
- }
-
- preload_storage_put_linker_info(ld_info);
- return NULL;
-}
-
-static struct vm_area_struct *__get_libc_vma(struct task_struct *task)
-{
- struct vm_area_struct *vma = NULL;
- struct bin_info *libc_info;
-
- libc_info = preload_storage_get_libc_info();
-
- if (!libc_info) {
- printk(PRELOAD_PREFIX "Cannot get libc info [%u %u %s]!\n",
- task->tgid, task->pid, task->comm);
- return NULL;
- }
-
- for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
- if (vma->vm_file && vma->vm_flags & VM_EXEC
- && vma->vm_file->f_dentry == libc_info->dentry) {
- preload_storage_put_libc_info(libc_info);
- return vma;
- }
- }
-
- preload_storage_put_libc_info(libc_info);
- return NULL;
-}
-
-static struct vm_area_struct *__get_libpthread_vma(struct task_struct *task)
-{
- struct vm_area_struct *vma = NULL;
- struct bin_info *libpthread_info;
-
- libpthread_info = preload_storage_get_libpthread_info();
-
- if (!libpthread_info) {
- printk(PRELOAD_PREFIX "Cannot get libpthread info [%u %u %s]!\n",
- task->tgid, task->pid, task->comm);
- return NULL;
- }
-
- for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
- if (vma->vm_file && vma->vm_flags & VM_EXEC
- && vma->vm_file->f_dentry == libpthread_info->dentry) {
- preload_storage_put_libpthread_info(libpthread_info);
- return vma;
- }
- }
-
- preload_storage_put_libpthread_info(libpthread_info);
- return NULL;
-}
-
-static struct vm_area_struct *__get_libsmack_vma(struct task_struct *task)
-{
- struct vm_area_struct *vma = NULL;
- struct bin_info *libsmack_info;
-
- libsmack_info = preload_storage_get_libsmack_info();
-
- if (!libsmack_info) {
- printk(PRELOAD_PREFIX "Cannot get libsmack info [%u %u %s]!\n",
- task->tgid, task->pid, task->comm);
- return NULL;
- }
-
- for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
- if (vma->vm_file && vma->vm_flags & VM_EXEC
- && vma->vm_file->f_dentry == libsmack_info->dentry) {
- preload_storage_put_libsmack_info(libsmack_info);
- return vma;
- }
- }
-
- preload_storage_put_libsmack_info(libsmack_info);
- return NULL;
-}
-
-static inline struct vm_area_struct *__get_vma_by_addr(struct task_struct *task,
- unsigned long caller_addr)
-{
- struct vm_area_struct *vma = NULL;
-
- if (task->mm == NULL)
- return NULL;
- vma = find_vma_intersection(task->mm, caller_addr, caller_addr + 1);
-
- return vma;
-}
-
-static inline bool __inverted(struct us_ip *ip)
-{
- unsigned long flags = ip->info->pl_i.flags;
-
- if (flags & SWAP_PRELOAD_INVERTED_PROBE)
- return true;
-
- return false;
-}
-
-static inline bool __should_drop(struct us_ip *ip, enum preload_call_type ct)
-{
- if (ct == NOT_INSTRUMENTED)
- return true;
-
- return false;
-}
-
-static inline bool __check_flag_and_call_type(struct us_ip *ip,
- enum preload_call_type ct)
-{
- bool inverted = __inverted(ip);
-
- if (ct != NOT_INSTRUMENTED || inverted)
- return true;
-
- return false;
-}
-
-static inline bool __is_probe_non_block(struct us_ip *ip)
-{
- if (ip->info->pl_i.flags & SWAP_PRELOAD_NON_BLOCK_PROBE)
- return true;
-
- return false;
-}
-
-static inline bool __is_handlers_call(struct vm_area_struct *caller)
-{
- /* TODO Optimize using start/stop callbacks */
-
- struct bin_info *hi = preload_storage_get_handlers_info();
- bool res = false;
-
- if (hi == NULL) {
- printk(PRELOAD_PREFIX "Cannot get handlers dentry!\n");
- goto is_handlers_call_out;
- }
-
- if (caller == NULL || caller->vm_file == NULL ||
- caller->vm_file->f_dentry == NULL) {
- goto is_handlers_call_out;
- }
-
- if (hi->dentry == caller->vm_file->f_dentry)
- res = true;
-
-is_handlers_call_out:
-
- preload_storage_put_handlers_info(hi);
-
- return res;
-}
-
-static inline int __msg_sanitization(char *user_msg, size_t len,
- char *call_type_p, char *caller_p)
-{
- if ((call_type_p < user_msg) || (call_type_p > user_msg + len) ||
- (caller_p < user_msg) || (caller_p > user_msg + len))
- return -EINVAL;
-
- return 0;
-}
-
-
-
-
-
-static bool __is_proc_mmap_mappable(struct task_struct *task)
-{
- struct vm_area_struct *linker_vma = __get_linker_vma(task);
- struct sspt_proc *proc;
- unsigned long r_debug_addr;
- unsigned int state;
- enum { r_state_offset = sizeof(int) + sizeof(void *) + sizeof(long) };
-
- if (linker_vma == NULL)
- return false;
-
- r_debug_addr = __get_r_debug_off(linker_vma);
- if (r_debug_addr == 0)
- return false;
-
- r_debug_addr += r_state_offset;
- proc = sspt_proc_get_by_task(task);
- if (proc)
- proc->r_state_addr = r_debug_addr;
-
- if (get_user(state, (unsigned long *)r_debug_addr))
- return false;
-
- return !state;
-}
-
-static bool __not_system_caller(struct task_struct *task,
- struct vm_area_struct *caller)
-{
- struct vm_area_struct *linker_vma = __get_linker_vma(task);
- struct vm_area_struct *libc_vma = __get_libc_vma(task);
- struct vm_area_struct *libpthread_vma = __get_libpthread_vma(task);
- struct vm_area_struct *libsmack_vma = __get_libsmack_vma(task);
-
- if (linker_vma == NULL ||
- libc_vma == NULL ||
- libpthread_vma == NULL ||
- libsmack_vma == NULL ||
- caller == NULL ||
- caller == linker_vma ||
- caller == libc_vma ||
- caller == libpthread_vma ||
- caller == libsmack_vma)
- return false;
-
- return true;
-}
-
-static bool __should_we_preload_handlers(struct task_struct *task,
- struct pt_regs *regs)
-{
- unsigned long caller_addr = get_regs_ret_func(regs);
- struct vm_area_struct *cvma = __get_vma_by_addr(current, caller_addr);
-
- if (!__is_proc_mmap_mappable(task) ||
- !__not_system_caller(task, cvma))
- return false;
-
- return true;
-}
-
-static inline void __write_data_to_msg(char *msg, size_t len,
- unsigned long call_type_off,
- unsigned long caller_off,
- unsigned long caller_addr)
-{
- unsigned char call_type = 0;
- unsigned long caller = 0;
- int ret;
-
- if (caller_addr != 0) {
- caller = caller_addr;
- call_type = preload_control_call_type_always_inst((void *)caller);
- } else {
- ret = preload_threads_get_caller(current, &caller);
- if (ret != 0) {
- caller = 0xbadbeef;
- printk(PRELOAD_PREFIX "Error! Cannot get caller address for %d/%d\n",
- current->tgid, current->pid);
- }
-
- ret = preload_threads_get_call_type(current, &call_type);
- if (ret != 0) {
- call_type = 0xff;
- printk(PRELOAD_PREFIX "Error! Cannot get call type for %d/%d\n",
- current->tgid, current->pid);
- }
- }
-
- /* Using the same types as in the library. */
- *(uint32_t *)(msg + call_type_off) = (uint32_t)call_type;
- *(uintptr_t *)(msg + caller_off) = (uintptr_t)caller;
-}
-
-
-
-
-enum mmap_type_t {
- MMAP_LOADER,
- MMAP_HANDLERS,
- MMAP_SKIP
-};
-
-struct mmap_priv {
- enum mmap_type_t type;
-};
-
-static inline bool check_prot(unsigned long prot)
-{
- return !!((prot & PROT_READ) && (prot & PROT_EXEC));
-}
-
-static int mmap_entry_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct file *file = (struct file *)swap_get_karg(regs, 0);
- unsigned long prot = swap_get_karg(regs, 3);
- struct mmap_priv *priv = (struct mmap_priv *)ri->data;
- struct dentry *dentry, *loader_dentry;
- struct bin_info *hi;
-
- priv->type = MMAP_SKIP;
- if (!check_prot(prot))
- return 0;
-
- if (!file)
- return 0;
- dentry = file->f_dentry;
- if (dentry == NULL)
- return 0;
-
- hi = preload_storage_get_handlers_info();
- if (hi == NULL) {
- printk(PRELOAD_PREFIX "Cannot get handlers info [%u %u %s]\n",
- current->tgid, current->pid, current->comm);
- return 0;
- }
-
- loader_dentry = preload_debugfs_get_loader_dentry();
- if (dentry == loader_dentry)
- priv->type = MMAP_LOADER;
- else if (hi->dentry != NULL && dentry == hi->dentry)
- priv->type = MMAP_HANDLERS;
-
- preload_storage_put_handlers_info(hi);
-
- return 0;
-}
-
-static int mmap_ret_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct mmap_priv *priv = (struct mmap_priv *)ri->data;
- struct task_struct *task = current->group_leader;
- struct process_data *pd;
- struct sspt_proc *proc;
- unsigned long vaddr;
-
- if (!task->mm)
- return 0;
-
- vaddr = (unsigned long)regs_return_value(regs);
- if (IS_ERR_VALUE(vaddr))
- return 0;
-
- proc = sspt_proc_get_by_task(task);
- if (!proc)
- return 0;
-
- pd = preload_pd_get(proc);
- if (pd == NULL) {
- printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n",
- __LINE__, current->tgid, current->comm);
- return 0;
- }
-
- switch (priv->type) {
- case MMAP_LOADER:
- preload_pd_set_loader_base(pd, vaddr);
- break;
- case MMAP_HANDLERS:
- preload_pd_set_handlers_base(pd, vaddr);
- break;
- case MMAP_SKIP:
- default:
- break;
- }
-
- return 0;
-}
-
-static struct kretprobe mmap_rp = {
- .kp.symbol_name = "do_mmap_pgoff",
- .data_size = sizeof(struct mmap_priv),
- .entry_handler = mmap_entry_handler,
- .handler = mmap_ret_handler
-};
-
-static void preload_start_cb(void)
-{
- int res;
-
- res = swap_register_kretprobe(&mmap_rp);
- if (res != 0)
- printk(KERN_ERR PRELOAD_PREFIX "Registering do_mmap_pgoff probe failed\n");
-}
-
-static void preload_stop_cb(void)
-{
- swap_unregister_kretprobe(&mmap_rp);
-}
-
-static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct process_data *pd = __get_process_data(ri->rp);
- struct us_ip *ip = container_of(ri->rp, struct us_ip, retprobe);
- struct us_priv *priv = (struct us_priv *)ri->data;
- unsigned long flags = get_preload_flags(current);
- unsigned long offset = ip->info->pl_i.handler;
- unsigned long vaddr = 0;
- unsigned long base;
- char __user *path = NULL;
-
- if ((flags & HANDLER_RUNNING) ||
- preload_threads_check_disabled_probe(current, ip->orig_addr))
- goto out_set_origin;
-
- switch (preload_pd_get_state(pd)) {
- case NOT_LOADED:
- /* if linker is still doing its work, we do nothing */
- if (!__should_we_preload_handlers(current, regs))
- goto out_set_origin;
-
- base = preload_pd_get_loader_base(pd);
- if (base == 0)
- break; /* loader isn't mapped */
-
- /* jump to loader code if ready */
- vaddr = base + preload_debugfs_get_loader_offset();
- if (vaddr) {
- /* save original regs state */
- __save_uregs(ri, regs);
- print_regs("ORIG", regs, ri);
-
- path = preload_pd_get_path(pd);
-
- /* set dlopen args: filename, flags */
- swap_set_arg(regs, 0, (unsigned long)path/*swap_get_stack_ptr(regs)*/);
- swap_set_arg(regs, 1, 2 /* RTLD_NOW */);
-
- /* do the jump to dlopen */
- __prepare_ujump(ri, regs, vaddr);
- /* set new state */
- preload_pd_set_state(pd, LOADING);
- }
- break;
- case LOADING:
- /* handlers have not yet been loaded... just ignore */
- break;
- case LOADED:
- base = preload_pd_get_handlers_base(pd);
- if (base == 0)
- break; /* handlers isn't mapped */
-
- /* jump to preloaded handler */
- vaddr = base + offset;
- if (vaddr) {
- unsigned long disable_addr;
- unsigned long caddr = get_regs_ret_func(regs);
- struct vm_area_struct *cvma = __get_vma_by_addr(current, caddr);
- enum preload_call_type ct;
-
- ct = preload_control_call_type(ip, (void *)caddr);
- disable_addr = __is_probe_non_block(ip) ?
- ip->orig_addr : 0;
-
- /* jump only if caller is instumented and it is not a system lib -
- * this leads to some errors */
- if (__not_system_caller(current, cvma) &&
- __check_flag_and_call_type(ip, ct) &&
- !__is_handlers_call(cvma)) {
- if (preload_threads_set_data(current,
- caddr, ct,
- disable_addr,
- __should_drop(ip,
- ct)) != 0)
- printk(PRELOAD_PREFIX "Error! Failed to set caller 0x%lx"
- " for %d/%d\n", caddr, current->tgid,
- current->pid);
- /* args are not changed */
- __prepare_ujump(ri, regs, vaddr);
- if (disable_addr == 0)
- set_preload_flags(current, HANDLER_RUNNING);
- }
- }
- break;
- case FAILED:
- case ERROR:
- default:
- /* do nothing */
- break;
- }
-
-out_set_origin:
- priv->origin = vaddr;
- return 0;
-}
-
-static int preload_us_ret(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct process_data *pd = __get_process_data(ri->rp);
- struct us_ip *ip = container_of(ri->rp, struct us_ip, retprobe);
- struct us_priv *priv = (struct us_priv *)ri->data;
- unsigned long flags = get_preload_flags(current);
- unsigned long offset = ip->info->pl_i.handler;
- unsigned long vaddr = 0;
-
- switch (preload_pd_get_state(pd)) {
- case NOT_LOADED:
- /* loader has not yet been mapped... just ignore */
- break;
- case LOADING:
- /* check if preloading has been completed */
- vaddr = preload_pd_get_loader_base(pd) + preload_debugfs_get_loader_offset();
- if (vaddr && (priv->origin == vaddr)) {
- preload_pd_set_handle(pd, (void __user *)regs_return_value(regs));
-
- /* restore original regs state */
- __restore_uregs(ri, regs);
- print_regs("REST", regs, ri);
- /* check if preloading done */
-
- if (preload_pd_get_handle(pd)) {
- preload_pd_set_state(pd, LOADED);
- preload_pd_put_path(pd);
- } else {
- preload_pd_dec_attempts(pd);
- preload_pd_set_state(pd, FAILED);
- preload_pd_put_path(pd);
- }
- }
- break;
- case LOADED:
- if ((flags & HANDLER_RUNNING) ||
- preload_threads_check_disabled_probe(current, ip->orig_addr)) {
- bool non_blk_probe = __is_probe_non_block(ip);
-
- /* drop the flag if the handler has completed */
- vaddr = preload_pd_get_handlers_base(pd) + offset;
- if (vaddr && (priv->origin == vaddr)) {
- if (preload_threads_put_data(current) != 0)
- printk(PRELOAD_PREFIX "Error! Failed to put caller slot"
- " for %d/%d\n", current->tgid, current->pid);
- if (!non_blk_probe) {
- flags &= ~HANDLER_RUNNING;
- set_preload_flags(current, flags);
- }
- }
- }
- break;
- case FAILED:
- if (preload_pd_get_attempts(pd)) {
- preload_pd_set_state(pd, NOT_LOADED);
- preload_pd_put_path(pd);
- }
- break;
- case ERROR:
- default:
- break;
- }
-
- return 0;
-}
-
-
-
-static int get_caller_handler(struct kprobe *p, struct pt_regs *regs)
-{
- unsigned long caller;
- int ret;
-
- ret = preload_threads_get_caller(current, &caller);
- if (ret != 0) {
- caller = 0xbadbeef;
- printk(PRELOAD_PREFIX "Error! Cannot get caller address for %d/%d\n",
- current->tgid, current->pid);
- }
-
- swap_put_uarg(regs, 0, caller);
-
- return 0;
-}
-
-static int get_call_type_handler(struct kprobe *p, struct pt_regs *regs)
-{
- unsigned char call_type;
- int ret;
-
- ret = preload_threads_get_call_type(current, &call_type);
- if (ret != 0) {
- call_type = 0xff;
- printk(PRELOAD_PREFIX "Error! Cannot get call type for %d/%d\n",
- current->tgid, current->pid);
- }
-
- swap_put_uarg(regs, 0, call_type);
-
- return 0;
-}
-
-static int write_msg_handler(struct kprobe *p, struct pt_regs *regs)
-{
- char *user_buf;
- char *buf;
- char *caller_p;
- char *call_type_p;
- size_t len;
- unsigned long caller_offset;
- unsigned long call_type_offset;
- unsigned long caller_addr;
- bool drop;
- int ret;
-
- /* FIXME: swap_get_uarg uses get_user(), it might sleep */
- user_buf = (char *)swap_get_uarg(regs, 0);
- len = swap_get_uarg(regs, 1);
- call_type_p = (char *)swap_get_uarg(regs, 2);
- caller_p = (char *)swap_get_uarg(regs, 3);
- caller_addr = swap_get_uarg(regs, 4);
-
- ret = __msg_sanitization(user_buf, len, call_type_p, caller_p);
- if (ret != 0) {
- printk(PRELOAD_PREFIX "Invalid message pointers!\n");
- return 0;
- }
-
- ret = preload_threads_get_drop(current, &drop);
- if (ret == 0 && drop)
- return 0;
-
- buf = kmalloc(len, GFP_ATOMIC);
- if (buf == NULL) {
- printk(PRELOAD_PREFIX "No mem for buffer! Size = %d\n", len);
- return 0;
- }
-
- ret = read_proc_vm_atomic(current, (unsigned long)user_buf, buf, len);
- if (ret < 0) {
- printk(PRELOAD_PREFIX "Cannot copy data from userspace! Size = %d"
- " ptr 0x%lx ret %d\n", len, (unsigned long)user_buf, ret);
- goto write_msg_fail;
- }
-
- /* Evaluating call_type and caller offset in message:
- * data offset = data pointer - beginning of the message.
- */
- call_type_offset = (unsigned long)(call_type_p - user_buf);
- caller_offset = (unsigned long)(caller_p - user_buf);
-
- __write_data_to_msg(buf, len, call_type_offset, caller_offset, caller_addr);
-
- ret = swap_msg_raw(buf, len);
- if (ret != len)
- printk(PRELOAD_PREFIX "Error writing probe lib message\n");
-
-write_msg_fail:
- kfree(buf);
-
- return 0;
-}
-
-
-
-
-int preload_module_get_caller_init(struct us_ip *ip)
-{
- struct uprobe *up = &ip->uprobe;
-
- up->kp.pre_handler = get_caller_handler;
-
- return 0;
-}
-
-void preload_module_get_caller_exit(struct us_ip *ip)
-{
-}
-
-int preload_module_get_call_type_init(struct us_ip *ip)
-{
- struct uprobe *up = &ip->uprobe;
-
- up->kp.pre_handler = get_call_type_handler;
-
- return 0;
-}
-
-void preload_module_get_call_type_exit(struct us_ip *ip)
-{
-}
-
-int preload_module_write_msg_init(struct us_ip *ip)
-{
- struct uprobe *up = &ip->uprobe;
-
- up->kp.pre_handler = write_msg_handler;
-
- return 0;
-}
-
-void preload_module_write_msg_exit(struct us_ip *ip)
-{
-}
-
-
-int preload_module_uprobe_init(struct us_ip *ip)
-{
- struct uretprobe *rp = &ip->retprobe;
-
- rp->entry_handler = preload_us_entry;
- rp->handler = preload_us_ret;
- /* FIXME actually additional data_size is needed only when we jump
- * to dlopen */
- rp->data_size = sizeof(struct us_priv);
-
- return 0;
-}
-
-void preload_module_uprobe_exit(struct us_ip *ip)
-{
-}
-
-int preload_set(void)
-{
- if (preload_module_is_running())
- return -EBUSY;
-
- return 0;
-}
-
-void preload_unset(void)
-{
- swap_unregister_kretprobe(&mmap_rp);
- /*module_put(THIS_MODULE);*/
- preload_module_set_not_ready();
-
-}
-
-static int preload_module_init(void)
-{
- int ret;
-
- ret = preload_debugfs_init();
- if (ret)
- goto out_err;
-
- ret = preload_storage_init();
- if (ret)
- goto exit_debugfs;
-
- ret = preload_pd_init();
- if (ret)
- goto exit_storage;
-
- /* TODO do not forget to remove set (it is just for debugging) */
- ret = preload_set();
- if (ret)
- goto exit_pd;
-
- ret = preload_control_init();
- if (ret)
- goto exit_set;
-
- ret = preload_threads_init();
- if (ret)
- goto exit_control;
-
- ret = register_preload_probes();
- if (ret)
- goto exit_threads;
-
- __preload_cbs_start_h = us_manager_reg_cb(START_CB, preload_start_cb);
- if (__preload_cbs_start_h < 0)
- goto exit_start_cb;
-
- __preload_cbs_stop_h = us_manager_reg_cb(STOP_CB, preload_stop_cb);
- if (__preload_cbs_stop_h < 0)
- goto exit_stop_cb;
-
- return 0;
-
-exit_stop_cb:
- us_manager_unreg_cb(__preload_cbs_start_h);
-
-exit_start_cb:
- unregister_preload_probes();
-
-exit_threads:
- preload_threads_exit();
-
-exit_control:
- preload_control_exit();
-
-exit_set:
- preload_unset();
-
-exit_pd:
- preload_pd_uninit();
-
-exit_storage:
- preload_storage_exit();
-
-exit_debugfs:
- preload_debugfs_exit();
-
-out_err:
- return ret;
-}
-
-static void preload_module_exit(void)
-{
- int balance;
-
- us_manager_unreg_cb(__preload_cbs_start_h);
- us_manager_unreg_cb(__preload_cbs_stop_h);
- unregister_preload_probes();
- preload_threads_exit();
- preload_control_exit();
- preload_unset();
- preload_pd_uninit();
- preload_storage_exit();
- preload_debugfs_exit();
-
- balance = atomic_read(&dentry_balance);
- atomic_set(&dentry_balance, 0);
-
- WARN(balance, "Bad GET/PUT dentry balance: %d\n", balance);
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, preload_module_init, preload_module_exit,
- NULL, NULL);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP Preload Module");
-MODULE_AUTHOR("Vasiliy Ulyanov <v.ulyanov@samsung.com>"
- "Alexander Aksenov <a.aksenov@samsung.com>");
+++ /dev/null
-#ifndef __PRELOAD_MODULE_H__
-#define __PRELOAD_MODULE_H__
-
-#include <linux/types.h>
-
-struct us_ip;
-struct dentry;
-
-bool preload_module_is_ready(void);
-bool preload_module_is_running(void);
-bool preload_module_is_not_ready(void);
-void preload_module_set_ready(void);
-void preload_module_set_running(void);
-void preload_module_set_not_ready(void);
-
-int preload_module_uprobe_init(struct us_ip *ip);
-void preload_module_uprobe_exit(struct us_ip *ip);
-
-int preload_module_get_caller_init(struct us_ip *ip);
-void preload_module_get_caller_exit(struct us_ip *ip);
-int preload_module_get_call_type_init(struct us_ip *ip);
-void preload_module_get_call_type_exit(struct us_ip *ip);
-int preload_module_write_msg_init(struct us_ip *ip);
-void preload_module_write_msg_exit(struct us_ip *ip);
-
-struct dentry *get_dentry(const char *filepath);
-void put_dentry(struct dentry *dentry);
-
-
-#endif /* __PRELOAD_MODULE_H__ */
+++ /dev/null
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/dcache.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/hardirq.h>
-#include <us_manager/us_manager_common.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include "preload_pd.h"
-#include "preload_threads.h"
-#include "preload_debugfs.h"
-#include "preload_storage.h"
-#include "preload.h"
-
-struct process_data {
- enum preload_state_t state;
- unsigned long loader_base;
- unsigned long handlers_base;
- unsigned long data_page;
- void __user *handle;
- long attempts;
- long refcount;
-};
-
-static struct bin_info *handlers_info;
-
-
-
-static inline bool check_vma(struct vm_area_struct *vma, struct dentry *dentry)
-{
- struct file *file = vma->vm_file;
-
- return (file && (vma->vm_flags & VM_EXEC) && (file->f_dentry == dentry));
-}
-
-static inline enum preload_state_t __get_state(struct process_data *pd)
-{
- return pd->state;
-}
-
-static inline void __set_state(struct process_data *pd,
- enum preload_state_t state)
-{
- pd->state = state;
-}
-
-static inline unsigned long __get_loader_base(struct process_data *pd)
-{
- return pd->loader_base;
-}
-
-static inline void __set_loader_base(struct process_data *pd,
- unsigned long addr)
-{
- pd->loader_base = addr;
-}
-
-static inline unsigned long __get_handlers_base(struct process_data *pd)
-{
- return pd->handlers_base;
-}
-
-static inline void __set_handlers_base(struct process_data *pd,
- unsigned long addr)
-{
- pd->handlers_base = addr;
-}
-
-static inline char __user *__get_path(struct process_data *pd)
-{
- return (char *)pd->data_page;
-}
-
-static inline unsigned long __get_data_page(struct process_data *pd)
-{
- return pd->data_page;
-}
-
-static inline void __set_data_page(struct process_data *pd, unsigned long page)
-{
- pd->data_page = page;
-}
-
-static inline void *__get_handle(struct process_data *pd)
-{
- return pd->handle;
-}
-
-static inline void __set_handle(struct process_data *pd, void __user *handle)
-{
- pd->handle = handle;
-}
-
-static inline long __get_attempts(struct process_data *pd)
-{
- return pd->attempts;
-}
-
-static inline void __set_attempts(struct process_data *pd, long attempts)
-{
- pd->attempts = attempts;
-}
-
-static inline long __get_refcount(struct process_data *pd)
-{
- return pd->refcount;
-}
-
-static inline void __set_refcount(struct process_data *pd, long refcount)
-{
- pd->refcount = refcount;
-}
-
-
-
-
-static int __pd_create_on_demand(void)
-{
- if (handlers_info == NULL) {
- handlers_info = preload_storage_get_handlers_info();
- if (handlers_info == NULL)
- return -EINVAL;
- }
-
- return 0;
-}
-
-
-
-enum preload_state_t preload_pd_get_state(struct process_data *pd)
-{
- if (pd == NULL)
- return 0;
-
- return __get_state(pd);
-}
-
-void preload_pd_set_state(struct process_data *pd, enum preload_state_t state)
-{
- if (pd == NULL) {
- printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
- current->tgid, current->comm);
- return;
- }
-
- __set_state(pd, state);
-}
-
-unsigned long preload_pd_get_loader_base(struct process_data *pd)
-{
- if (pd == NULL)
- return 0;
-
- return __get_loader_base(pd);
-}
-
-void preload_pd_set_loader_base(struct process_data *pd, unsigned long vaddr)
-{
- __set_loader_base(pd, vaddr);
-}
-
-unsigned long preload_pd_get_handlers_base(struct process_data *pd)
-{
- if (pd == NULL)
- return 0;
-
- return __get_handlers_base(pd);
-}
-
-void preload_pd_set_handlers_base(struct process_data *pd, unsigned long vaddr)
-{
- __set_handlers_base(pd, vaddr);
-}
-
-void preload_pd_put_path(struct process_data *pd)
-{
- if (pd == NULL) {
- printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
- current->tgid, current->comm);
- return;
- }
-
- if (__get_data_page(pd) == 0)
- return;
-
- __set_data_page(pd, 0);
-}
-
-char __user *preload_pd_get_path(struct process_data *pd)
-{
- char __user *path = __get_path(pd);
-
- return path;
-}
-
-
-
-void *preload_pd_get_handle(struct process_data *pd)
-{
- if (pd == NULL)
- return NULL;
-
- return __get_handle(pd);
-}
-
-void preload_pd_set_handle(struct process_data *pd, void __user *handle)
-{
- if (pd == NULL) {
- printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
- current->tgid, current->comm);
- return;
- }
-
- __set_handle(pd, handle);
-}
-
-long preload_pd_get_attempts(struct process_data *pd)
-{
- if (pd == NULL)
- return -EINVAL;
-
- return __get_attempts(pd);
-}
-
-void preload_pd_dec_attempts(struct process_data *pd)
-{
- long attempts;
-
- if (pd == NULL) {
- printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
- current->tgid, current->comm);
- return;
- }
-
- attempts = __get_attempts(pd);
- attempts--;
- __set_attempts(pd, attempts);
-}
-
-void preload_pd_inc_refs(struct process_data *pd)
-{
- long refs;
-
- if (pd == NULL) {
- printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
- current->tgid, current->comm);
- return;
- }
-
- refs = __get_refcount(pd);
- refs++;
- __set_refcount(pd, refs);
-}
-
-void preload_pd_dec_refs(struct process_data *pd)
-{
- long refs;
-
- if (pd == NULL) {
- printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
- current->tgid, current->comm);
- return;
- }
-
- refs = __get_refcount(pd);
- refs--;
- __set_refcount(pd, refs);
-}
-
-long preload_pd_get_refs(struct process_data *pd)
-{
- if (pd == NULL)
- return -EINVAL;
-
- return __get_refcount(pd);
-}
-
-struct process_data *preload_pd_get(struct sspt_proc *proc)
-{
- return (struct process_data *)proc->private_data;
-}
-
-static unsigned long make_preload_path(void)
-{
- unsigned long page = -EINVAL;
-
- if (handlers_info) {
- const char *path = handlers_info->path;
- size_t len = strnlen(path, PATH_MAX);
-
- down_write(¤t->mm->mmap_sem);
- page = swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_PRIVATE, 0);
- up_write(¤t->mm->mmap_sem);
-
- if (IS_ERR_VALUE(page)) {
- printk(KERN_ERR PRELOAD_PREFIX
- "Cannot alloc page for %u\n", current->tgid);
- goto out;
- }
-
- /* set preload_library path */
- if (copy_to_user((void __user *)page, path, len) != 0)
- printk(KERN_ERR PRELOAD_PREFIX
- "Cannot copy string to user!\n");
- }
-
-out:
- return page;
-}
-
-static struct vm_area_struct *find_vma_by_dentry(struct mm_struct *mm,
- struct dentry *dentry)
-{
- struct vm_area_struct *vma;
-
- for (vma = mm->mmap; vma; vma = vma->vm_next)
- if (check_vma(vma, dentry))
- return vma;
-
- return NULL;
-}
-
-static void set_already_mapp(struct process_data *pd, struct mm_struct *mm)
-{
- struct vm_area_struct *vma;
- struct dentry *ld = preload_debugfs_get_loader_dentry();
- struct dentry *handlers = handlers_info->dentry;
-
- down_read(&mm->mmap_sem);
- if (ld) {
- vma = find_vma_by_dentry(mm, ld);
- if (vma)
- __set_loader_base(pd, vma->vm_start);
- }
-
- if (handlers) {
- vma = find_vma_by_dentry(mm, handlers);
- if (vma) {
- __set_handlers_base(pd, vma->vm_start);
- __set_state(pd, LOADED);
- }
- }
- up_read(&mm->mmap_sem);
-}
-
-static struct process_data *do_create_pd(struct task_struct *task)
-{
- struct process_data *pd;
- unsigned long page;
- int ret;
-
- ret = __pd_create_on_demand();
- if (ret)
- goto create_pd_exit;
-
- pd = kzalloc(sizeof(*pd), GFP_ATOMIC);
- if (pd == NULL) {
- ret = -ENOMEM;
- goto create_pd_exit;
- }
-
- page = make_preload_path();
- if (IS_ERR_VALUE(page)) {
- ret = (long)page;
- goto free_pd;
- }
-
- __set_data_page(pd, page);
- __set_attempts(pd, PRELOAD_MAX_ATTEMPTS);
- set_already_mapp(pd, task->mm);
-
- return pd;
-
-free_pd:
- kfree(pd);
-
-create_pd_exit:
- printk(KERN_ERR PRELOAD_PREFIX "do_pd_create_pd: error=%d\n", ret);
- return NULL;
-}
-
-static void *pd_create(struct sspt_proc *proc)
-{
- struct process_data *pd;
-
- pd = do_create_pd(proc->task);
-
- return (void *)pd;
-}
-
-static void pd_destroy(struct sspt_proc *proc, void *data)
-{
- /* FIXME: to be implemented */
-}
-
-struct sspt_proc_cb pd_cb = {
- .priv_create = pd_create,
- .priv_destroy = pd_destroy
-};
-
-int preload_pd_init(void)
-{
- int ret;
-
- ret = sspt_proc_cb_set(&pd_cb);
-
- return ret;
-}
-
-void preload_pd_uninit(void)
-{
- sspt_proc_cb_set(NULL);
-
- if (handlers_info)
- preload_storage_put_handlers_info(handlers_info);
- handlers_info = NULL;
-}
+++ /dev/null
-#ifndef __PRELOAD_PD_H__
-#define __PRELOAD_PD_H__
-
-struct process_data;
-struct sspt_proc;
-
-/* process preload states */
-enum preload_state_t {
- NOT_LOADED,
- LOADING,
- LOADED,
- FAILED,
- ERROR
-};
-
-struct process_data *preload_pd_get(struct sspt_proc *proc);
-
-enum preload_state_t preload_pd_get_state(struct process_data *pd);
-void preload_pd_set_state(struct process_data *pd, enum preload_state_t state);
-unsigned long preload_pd_get_loader_base(struct process_data *pd);
-void preload_pd_set_loader_base(struct process_data *pd, unsigned long vaddr);
-unsigned long preload_pd_get_handlers_base(struct process_data *pd);
-void preload_pd_set_handlers_base(struct process_data *pd, unsigned long vaddr);
-void *preload_pd_get_handle(struct process_data *pd);
-void preload_pd_set_handle(struct process_data *pd, void __user *handle);
-
-long preload_pd_get_attempts(struct process_data *pd);
-void preload_pd_dec_attempts(struct process_data *pd);
-
-void preload_pd_inc_refs(struct process_data *pd);
-void preload_pd_dec_refs(struct process_data *pd);
-long preload_pd_get_refs(struct process_data *pd);
-
-char __user *preload_pd_get_path(struct process_data *pd);
-void preload_pd_put_path(struct process_data *pd);
-
-int preload_pd_init(void);
-void preload_pd_uninit(void);
-
-
-#endif /* __PRELOAD_PD_H__*/
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/probes/preload_probe.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Alexander Aksenov: Preload implement
- *
- */
-
-#include <linux/module.h>
-#include <us_manager/us_manager.h>
-#include <us_manager/probes/register_probes.h>
-#include <us_manager/sspt/sspt_page.h>
-#include <uprobe/swap_uprobes.h>
-#include <us_manager/sspt/ip.h>
-#include "preload_probe.h"
-#include "preload.h"
-#include "preload_module.h"
-#include "preload_debugfs.h"
-
-static unsigned long long probes_count = 0;
-
-static int preload_info_copy(struct probe_info *dest,
- const struct probe_info *source)
-{
- memcpy(dest, source, sizeof(*source));
-
- return 0;
-}
-
-static void preload_info_cleanup(struct probe_info *probe_i)
-{
-}
-
-static struct uprobe *preload_get_uprobe(struct us_ip *ip)
-{
- return &ip->retprobe.up;
-}
-
-/* We count all preload probes to know current state of the preload module:
- * if there are registered probes, than it is currently running, if there is no
- * probes, module is just ready to be used.
- *
- * If there was no registered probes and now they're appeared, change state to
- * 'running'.
- */
-static inline void inc_probes(void)
-{
- if (probes_count == 0)
- preload_module_set_running();
-
- probes_count++;
-}
-
-/* If there were probes, but now there's no of them, change state to 'ready'.
- */
-static inline void dec_probes(void)
-{
- if (unlikely(probes_count == 0))
- printk(KERN_ERR PRELOAD_PREFIX "Trying to remove probe when there is no one!\n");
-
- probes_count--;
- if (probes_count == 0)
- preload_module_set_ready();
-}
-
-/* Checks if preload can be in 'ready' state. It is so, if loader's dentry and
- * offset are specified.
- */
-static inline bool can_be_ready(void)
-{
- struct dentry *dentry = preload_debugfs_get_loader_dentry();
- unsigned long offset = preload_debugfs_get_loader_offset();
-
- if (dentry != NULL && offset != 0)
- return true;
-
- return false;
-}
-
-/* Registers probe if preload is 'running' or 'ready'.
- */
-static int preload_register_probe(struct us_ip *ip)
-{
- if (preload_module_is_not_ready()) {
- if (can_be_ready()) {
- preload_module_set_ready();
- } else {
- printk(PRELOAD_PREFIX "Module is not initialized!\n");
- return -EINVAL;
- }
- }
-
- inc_probes();
-
- return swap_register_uretprobe(&ip->retprobe);
-}
-
-static void preload_unregister_probe(struct us_ip *ip, int disarm)
-{
- __swap_unregister_uretprobe(&ip->retprobe, disarm);
-
- dec_probes();
-}
-
-static void preload_init(struct us_ip *ip)
-{
- preload_module_uprobe_init(ip);
-}
-
-static void preload_uninit(struct us_ip *ip)
-{
- preload_module_uprobe_exit(ip);
-
- preload_info_cleanup(ip->info);
-}
-
-static struct probe_iface preload_iface = {
- .init = preload_init,
- .uninit = preload_uninit,
- .reg = preload_register_probe,
- .unreg = preload_unregister_probe,
- .get_uprobe = preload_get_uprobe,
- .copy = preload_info_copy,
- .cleanup = preload_info_cleanup
-};
-
-static int get_caller_info_copy(struct probe_info *dest,
- const struct probe_info *source)
-{
- memcpy(dest, source, sizeof(*source));
-
- return 0;
-}
-
-static void get_caller_info_cleanup(struct probe_info *probe_i)
-{
-}
-
-static struct uprobe *get_caller_get_uprobe(struct us_ip *ip)
-{
- return &ip->uprobe;
-}
-
-static int get_caller_register_probe(struct us_ip *ip)
-{
- return swap_register_uprobe(&ip->uprobe);
-}
-
-static void get_caller_unregister_probe(struct us_ip *ip, int disarm)
-{
- __swap_unregister_uprobe(&ip->uprobe, disarm);
-}
-
-static void get_caller_init(struct us_ip *ip)
-{
- preload_module_get_caller_init(ip);
-}
-
-static void get_caller_uninit(struct us_ip *ip)
-{
- preload_module_get_caller_exit(ip);
-
- get_caller_info_cleanup(ip->info);
-}
-
-static struct probe_iface get_caller_iface = {
- .init = get_caller_init,
- .uninit = get_caller_uninit,
- .reg = get_caller_register_probe,
- .unreg = get_caller_unregister_probe,
- .get_uprobe = get_caller_get_uprobe,
- .copy = get_caller_info_copy,
- .cleanup = get_caller_info_cleanup
-};
-
-static void get_call_type_init(struct us_ip *ip)
-{
- preload_module_get_call_type_init(ip);
-}
-
-static void get_call_type_uninit(struct us_ip *ip)
-{
- preload_module_get_call_type_exit(ip);
-
- get_caller_info_cleanup(ip->info);
-}
-
-static struct probe_iface get_call_type_iface = {
- .init = get_call_type_init,
- .uninit = get_call_type_uninit,
- .reg = get_caller_register_probe,
- .unreg = get_caller_unregister_probe,
- .get_uprobe = get_caller_get_uprobe,
- .copy = get_caller_info_copy,
- .cleanup = get_caller_info_cleanup
-};
-
-static void write_msg_init(struct us_ip *ip)
-{
- preload_module_write_msg_init(ip);
-}
-
-static int write_msg_reg(struct us_ip *ip)
-{
- ip->uprobe.atomic_ctx = false;
-
- return get_caller_register_probe(ip);
-}
-
-static void write_msg_uninit(struct us_ip *ip)
-{
- preload_module_write_msg_exit(ip);
-
- get_caller_info_cleanup(ip->info);
-}
-
-static struct probe_iface write_msg_iface = {
- .init = write_msg_init,
- .uninit = write_msg_uninit,
- .reg = write_msg_reg,
- .unreg = get_caller_unregister_probe,
- .get_uprobe = get_caller_get_uprobe,
- .copy = get_caller_info_copy,
- .cleanup = get_caller_info_cleanup
-};
-
-int register_preload_probes(void)
-{
- int ret;
-
- ret = swap_register_probe_type(SWAP_PRELOAD_PROBE, &preload_iface);
- if (ret != 0)
- return ret;
-
- ret = swap_register_probe_type(SWAP_GET_CALLER, &get_caller_iface);
- if (ret != 0)
- return ret;
-
- ret = swap_register_probe_type(SWAP_GET_CALL_TYPE, &get_call_type_iface);
- if (ret != 0)
- return ret;
-
- ret = swap_register_probe_type(SWAP_WRITE_MSG, &write_msg_iface);
- return ret;
-}
-
-void unregister_preload_probes(void)
-{
- swap_unregister_probe_type(SWAP_PRELOAD_PROBE);
- swap_unregister_probe_type(SWAP_GET_CALLER);
- swap_unregister_probe_type(SWAP_GET_CALL_TYPE);
- swap_unregister_probe_type(SWAP_WRITE_MSG);
-}
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/probes/preload_probe.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Alexander Aksenov: FBI implement
- *
- */
-
-#ifndef __PRELOAD_PROBE_H__
-#define __PRELOAD_PROBE_H__
-
-/* Probe flags description:
- *
- * 0 - handler is ran only when probe has fired from a target binary;
- * 1 - handler is always ran;
- *
- * 00 - probe is disabling internal probes;
- * 10 - probe is non blocking one;
- *
- * 000 - probe is executed for instrumented binaries
- * 100 - probe is executed for non-instrumented binaries
- */
-
-enum {
- SWAP_PRELOAD_ALWAYS_RUN = (1 << 0),
- SWAP_PRELOAD_NON_BLOCK_PROBE = (1 << 1),
- SWAP_PRELOAD_INVERTED_PROBE = (1 << 2)
-};
-
-/* Preload probe info. */
-struct preload_info {
- unsigned long handler; /* Handler offset in probe library. */
- unsigned char flags; /* Preload probe flags. */
-};
-
-/* Get caller probe info */
-struct get_caller_info {
-};
-
-/* Get call type probe info */
-struct get_call_type_info {
-};
-
-/* Write message probe info */
-struct write_msg_info {
-};
-
-int register_preload_probes(void);
-void unregister_preload_probes(void);
-
-#endif /* __URETPROBE_H__ */
+++ /dev/null
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <ks_features/ks_map.h>
-#include <linux/fs.h>
-#include "preload.h"
-#include "preload_module.h"
-#include "preload_storage.h"
-
-static struct bin_info __handlers_info = { NULL, NULL };
-static struct bin_info __linker_info = { NULL, NULL };
-static struct bin_info __libc_info;
-static struct bin_info __libpthread_info;
-static struct bin_info __libsmack_info;
-
-static inline struct bin_info *__get_handlers_info(void)
-{
- return &__handlers_info;
-}
-
-static inline bool __check_handlers_info(void)
-{
- return (__handlers_info.dentry != NULL); /* TODO */
-}
-
-static inline int __init_handlers_info(char *path)
-{
- struct dentry *dentry;
- size_t len = strnlen(path, PATH_MAX);
- int ret = 0;
-
- __handlers_info.path = kmalloc(len + 1, GFP_KERNEL);
- if (__handlers_info.path == NULL) {
- ret = -ENOMEM;
- goto init_handlers_fail;
- }
-
- dentry = get_dentry(path);
- if (!dentry) {
- ret = -ENOENT;
- goto init_handlers_fail_free;
- }
-
- strncpy(__handlers_info.path, path, len);
- __handlers_info.path[len] = '\0';
- __handlers_info.dentry = dentry;
-
- return ret;
-
-init_handlers_fail_free:
- kfree(__handlers_info.path);
-
-init_handlers_fail:
- return ret;
-}
-
-static inline void __drop_handlers_info(void)
-{
- kfree(__handlers_info.path);
- __handlers_info.path = NULL;
-
- if (__handlers_info.dentry)
- put_dentry(__handlers_info.dentry);
- __handlers_info.dentry = NULL;
-}
-
-static inline struct bin_info *__get_linker_info(void)
-{
- return &__linker_info;
-}
-
-static inline bool __check_linker_info(void)
-{
- return (__linker_info.dentry != NULL); /* TODO */
-}
-
-static inline int __init_linker_info(char *path)
-{
- struct dentry *dentry;
- size_t len = strnlen(path, PATH_MAX);
- int ret = 0;
-
-
- __linker_info.path = kmalloc(len + 1, GFP_KERNEL);
- if (__linker_info.path == NULL) {
- ret = -ENOMEM;
- goto init_linker_fail;
- }
-
- dentry = get_dentry(path);
- if (!dentry) {
- ret = -ENOENT;
- goto init_linker_fail_free;
- }
-
- strncpy(__linker_info.path, path, len);
- __linker_info.path[len] = '\0';
- __linker_info.dentry = dentry;
-
- return ret;
-
-init_linker_fail_free:
- kfree(__linker_info.path);
-
-init_linker_fail:
-
- return ret;
-}
-
-static inline void __drop_linker_info(void)
-{
- kfree(__linker_info.path);
- __linker_info.path = NULL;
-
- if (__linker_info.dentry)
- put_dentry(__linker_info.dentry);
- __linker_info.dentry = NULL;
-}
-
-
-
-
-int preload_storage_set_handlers_info(char *path)
-{
- return __init_handlers_info(path);
-}
-
-struct bin_info *preload_storage_get_handlers_info(void)
-{
- struct bin_info *info = __get_handlers_info();
-
- if (__check_handlers_info())
- return info;
-
- return NULL;
-}
-
-void preload_storage_put_handlers_info(struct bin_info *info)
-{
-}
-
-int preload_storage_set_linker_info(char *path)
-{
- return __init_linker_info(path);
-}
-
-struct bin_info *preload_storage_get_linker_info(void)
-{
- struct bin_info *info = __get_linker_info();
-
- if (__check_linker_info())
- return info;
-
- return NULL;
-}
-
-static inline void __drop_libc_info(void)
-{
- if (__libc_info.dentry)
- put_dentry(__libc_info.dentry);
-
- __libc_info.path = NULL;
- __libc_info.dentry = NULL;
-}
-
-static inline void __drop_libpthread_info(void)
-{
- if (__libpthread_info.dentry)
- put_dentry(__libpthread_info.dentry);
-
- __libpthread_info.path = NULL;
- __libpthread_info.dentry = NULL;
-}
-
-static inline void __drop_libsmack_info(void)
-{
- if (__libsmack_info.dentry)
- put_dentry(__libsmack_info.dentry);
-
- __libsmack_info.path = NULL;
- __libsmack_info.dentry = NULL;
-}
-
-void preload_storage_put_linker_info(struct bin_info *info)
-{
-}
-
-struct bin_info *preload_storage_get_libc_info(void)
-{
- return &__libc_info;
-}
-
-struct bin_info *preload_storage_get_libpthread_info(void)
-{
- return &__libpthread_info;
-}
-
-struct bin_info *preload_storage_get_libsmack_info(void)
-{
- return &__libsmack_info;
-}
-
-void preload_storage_put_libc_info(struct bin_info *info)
-{
-}
-
-void preload_storage_put_libpthread_info(struct bin_info *info)
-{
-}
-
-void preload_storage_put_libsmack_info(struct bin_info *info)
-{
-}
-
-int preload_storage_init(void)
-{
- __libc_info.path = "/lib/libc.so.6";
- __libc_info.dentry = get_dentry(__libc_info.path);
-
- if (!__libc_info.dentry)
- return -ENOENT;
-
- /* TODO check if we have not library */
- __libpthread_info.path = "/lib/libpthread.so.0";
- __libpthread_info.dentry = get_dentry(__libpthread_info.path);
-
- if (!__libpthread_info.dentry)
- return -ENOENT;
-
- /* TODO check if we have not library */
- __libsmack_info.path = "/usr/lib/libsmack.so.1.0.0";
- __libsmack_info.dentry = get_dentry(__libsmack_info.path);
-
- if (!__libsmack_info.dentry)
- return -ENOENT;
-
- return 0;
-}
-
-void preload_storage_exit(void)
-{
- __drop_libsmack_info();
- __drop_libpthread_info();
- __drop_libc_info();
- __drop_handlers_info();
- __drop_linker_info();
-}
+++ /dev/null
-#ifndef __PRELOAD_STORAGE_H__
-#define __PRELOAD_STORAGE_H__
-
-struct bin_info {
- char *path;
- /* ghot */
- struct dentry *dentry;
-};
-
-int preload_storage_set_handlers_info(char *path);
-struct bin_info *preload_storage_get_handlers_info(void);
-void preload_storage_put_handlers_info(struct bin_info *info);
-
-int preload_storage_set_linker_info(char *path);
-struct bin_info *preload_storage_get_linker_info(void);
-void preload_storage_put_linker_info(struct bin_info *info);
-
-struct bin_info *preload_storage_get_libc_info(void);
-void preload_storage_put_libc_info(struct bin_info *info);
-
-struct bin_info *preload_storage_get_libpthread_info(void);
-void preload_storage_put_libpthread_info(struct bin_info *info);
-
-struct bin_info *preload_storage_get_libsmack_info(void);
-void preload_storage_put_libsmack_info(struct bin_info *info);
-
-int preload_storage_init(void);
-void preload_storage_exit(void);
-
-#endif /* __PRELOAD_HANDLERS_H__ */
+++ /dev/null
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/list.h>
-#include <task_data/task_data.h>
-#include "preload.h"
-#include "preload_threads.h"
-#include "preload_debugfs.h"
-#include "preload_pd.h"
-
-struct preload_td {
- struct list_head slots;
- unsigned long flags;
-};
-
-struct thread_slot {
- struct list_head list;
- struct list_head disabled_addrs;
-
- unsigned long caller;
- unsigned char call_type;
- bool drop; /* TODO Workaround, remove when will be possible to install
- * several us probes at the same addr. */
-};
-
-struct disabled_addr {
- struct list_head list;
- unsigned long addr;
-};
-
-static inline struct preload_td *get_preload_td(struct task_struct *task)
-{
- struct preload_td *td = NULL;
- int ok;
-
- td = swap_task_data_get(task, &ok);
- WARN(!ok, "Preload td[%d/%d] seems corrupted", task->tgid, task->pid);
-
- if (!td) {
- td = kzalloc(sizeof(*td), GFP_ATOMIC);
- WARN(!td, "Failed to allocate preload_td");
-
- if (td) {
- INIT_LIST_HEAD(&td->slots);
- /* We use SWAP_TD_FREE flag, i.e. the data will be
- * kfree'd by task_data module. */
- swap_task_data_set(task, td, SWAP_TD_FREE);
- }
- }
-
- return td;
-}
-
-unsigned long get_preload_flags(struct task_struct *task)
-{
- struct preload_td *td = get_preload_td(task);
-
- if (td == NULL)
- return 0;
-
- return td->flags;
-}
-
-void set_preload_flags(struct task_struct *task,
- unsigned long flags)
-{
- struct preload_td *td = get_preload_td(task);
-
- if (td == NULL) {
- printk(KERN_ERR "%s: invalid arguments\n", __FUNCTION__);
- return;
- }
-
- td->flags = flags;
-}
-
-
-static inline bool __is_addr_found(struct disabled_addr *da,
- unsigned long addr)
-{
- if (da->addr == addr)
- return true;
-
- return false;
-}
-
-static inline void __remove_from_disable_list(struct disabled_addr *da)
-{
- list_del(&da->list);
- kfree(da);
-}
-
-static inline void __remove_whole_disable_list(struct thread_slot *slot)
-{
- struct disabled_addr *da, *n;
-
- list_for_each_entry_safe(da, n, &slot->disabled_addrs, list)
- __remove_from_disable_list(da);
-}
-
-static inline void __init_slot(struct thread_slot *slot)
-{
- slot->caller = 0;
- slot->call_type = 0;
- slot->drop = false;
- INIT_LIST_HEAD(&slot->disabled_addrs);
-}
-
-static inline void __reinit_slot(struct thread_slot *slot)
-{
- __remove_whole_disable_list(slot);
- __init_slot(slot);
-}
-
-static inline void __set_slot(struct thread_slot *slot,
- struct task_struct *task, unsigned long caller,
- unsigned char call_type, bool drop)
-{
- slot->caller = caller;
- slot->call_type = call_type;
- slot->drop = drop;
-}
-
-static inline int __add_to_disable_list(struct thread_slot *slot,
- unsigned long disable_addr)
-{
- struct disabled_addr *da = kmalloc(sizeof(*da), GFP_ATOMIC);
-
- if (da == NULL)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&da->list);
- da->addr = disable_addr;
- list_add_tail(&da->list, &slot->disabled_addrs);
-
- return 0;
-}
-
-static inline struct disabled_addr *__find_disabled_addr(struct thread_slot *slot,
- unsigned long addr)
-{
- struct disabled_addr *da;
-
- list_for_each_entry(da, &slot->disabled_addrs, list)
- if (__is_addr_found(da, addr))
- return da;
-
- return NULL;
-}
-
-/* Adds a new slot */
-static inline struct thread_slot *__grow_slot(void)
-{
- struct thread_slot *tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);
-
- if (tmp == NULL)
- return NULL;
-
- INIT_LIST_HEAD(&tmp->list);
- __init_slot(tmp);
-
- return tmp;
-}
-
-/* Free slot */
-static void __clean_slot(struct thread_slot *slot)
-{
- list_del(&slot->list);
- kfree(slot);
-}
-
-/* There is no list_last_entry in Linux 3.10 */
-#ifndef list_last_entry
-#define list_last_entry(ptr, type, member) \
- list_entry((ptr)->prev, type, member)
-#endif /* list_last_entry */
-
-static inline struct thread_slot *__get_task_slot(struct task_struct *task)
-{
- struct preload_td *td = get_preload_td(task);
-
- if (td == NULL)
- return NULL;
-
- return list_empty(&td->slots) ? NULL :
- list_last_entry(&td->slots, struct thread_slot, list);
-}
-
-
-
-
-int preload_threads_set_data(struct task_struct *task, unsigned long caller,
- unsigned char call_type,
- unsigned long disable_addr, bool drop)
-{
- struct preload_td *td = get_preload_td(task);
- struct thread_slot *slot;
- int ret = 0;
-
- slot = __grow_slot();
- if (slot == NULL) {
- ret = -ENOMEM;
- goto set_data_done;
- }
-
- if ((disable_addr != 0) &&
- (__add_to_disable_list(slot, disable_addr) != 0)) {
- printk(KERN_ERR PRELOAD_PREFIX "Cannot alloc memory!\n");
- ret = -ENOMEM;
- goto set_data_done;
- }
-
- __set_slot(slot, task, caller, call_type, drop);
- list_add_tail(&slot->list, &td->slots);
-
-set_data_done:
- return ret;
-}
-
-int preload_threads_get_caller(struct task_struct *task, unsigned long *caller)
-{
- struct thread_slot *slot;
- int ret = 0;
-
- slot = __get_task_slot(task);
- if (slot != NULL) {
- *caller = slot->caller;
- goto get_caller_done;
- }
-
- /* If we're here - slot was not found */
- ret = -EINVAL;
-
-get_caller_done:
- return ret;
-}
-
-int preload_threads_get_call_type(struct task_struct *task,
- unsigned char *call_type)
-{
- struct thread_slot *slot;
- int ret = 0;
-
- slot = __get_task_slot(task);
- if (slot != NULL) {
- *call_type = slot->call_type;
- goto get_call_type_done;
- }
-
- /* If we're here - slot was not found */
- ret = -EINVAL;
-
-get_call_type_done:
- return ret;
-}
-
-int preload_threads_get_drop(struct task_struct *task, bool *drop)
-{
- struct thread_slot *slot;
- int ret = 0;
-
- slot = __get_task_slot(task);
- if (slot != NULL) {
- *drop = slot->drop;
- goto get_drop_done;
- }
-
- /* If we're here - slot was not found */
- ret = -EINVAL;
-
-get_drop_done:
- return ret;
-}
-
-bool preload_threads_check_disabled_probe(struct task_struct *task,
- unsigned long addr)
-{
- struct thread_slot *slot;
- bool ret = false;
-
- slot = __get_task_slot(task);
- if (slot != NULL)
- ret = __find_disabled_addr(slot, addr) == NULL ? false : true;
-
- return ret;
-}
-
-void preload_threads_enable_probe(struct task_struct *task, unsigned long addr)
-{
- struct thread_slot *slot;
- struct disabled_addr *da;
-
- slot = __get_task_slot(task);
- if (slot == NULL) {
- printk(KERN_ERR PRELOAD_PREFIX "Error! Slot not found!\n");
- goto enable_probe_failed;
- }
-
- da = __find_disabled_addr(slot, addr);
- if (da != NULL)
- __remove_from_disable_list(da);
-
-enable_probe_failed:
- return; /* make gcc happy: cannot place label right before '}' */
-}
-
-int preload_threads_put_data(struct task_struct *task)
-{
- struct thread_slot *slot;
- int ret = 0;
-
- slot = __get_task_slot(task);
- if (slot != NULL) {
- __reinit_slot(slot);
- __clean_slot(slot); /* remove from list */
- goto put_data_done;
- }
-
-put_data_done:
- return ret;
-}
-
-int preload_threads_init(void)
-{
- return 0;
-}
-
-void preload_threads_exit(void)
-{
-}
+++ /dev/null
-#ifndef __PRELOAD_THREADS_H__
-#define __PRELOAD_THREADS_H__
-
-struct task_struct;
-
-unsigned long get_preload_flags(struct task_struct *task);
-void set_preload_flags(struct task_struct *task,
- unsigned long flags);
-
-int preload_threads_set_data(struct task_struct *task, unsigned long caller,
- unsigned char call_type,
- unsigned long disable_addr, bool drop);
-int preload_threads_get_caller(struct task_struct *task, unsigned long *caller);
-int preload_threads_get_call_type(struct task_struct *task,
- unsigned char *call_type);
-int preload_threads_get_drop(struct task_struct *task, bool *drop);
-bool preload_threads_check_disabled_probe(struct task_struct *task,
- unsigned long addr);
-void preload_threads_enable_probe(struct task_struct *task, unsigned long addr);
-int preload_threads_put_data(struct task_struct *task);
-int preload_threads_init(void);
-void preload_threads_exit(void);
-
-#endif /* __PRELOAD_THREADS_H__ */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_retprobe.o
-swap_retprobe-y := \
- retprobe.o \
- rp_msg.o
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/retprobe/retprobe.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Alexander Aksenov: Probes interface implement
- *
- */
-
-#include "retprobe.h"
-#include <us_manager/us_manager.h>
-#include <us_manager/sspt/ip.h>
-#include <us_manager/probes/register_probes.h>
-#include <uprobe/swap_uprobes.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include "rp_msg.h"
-
-
-static int retprobe_copy(struct probe_info *dest,
- const struct probe_info *source)
-{
- size_t len;
-
- memcpy(dest, source, sizeof(*source));
-
- len = strlen(source->rp_i.args) + 1;
- dest->rp_i.args = kmalloc(len, GFP_ATOMIC);
- if (dest->rp_i.args == NULL)
- return -ENOMEM;
- memcpy(dest->rp_i.args, source->rp_i.args, len);
-
- return 0;
-}
-
-
-static void retprobe_cleanup(struct probe_info *probe_i)
-{
- kfree(probe_i->rp_i.args);
-}
-
-
-
-static struct uprobe *retprobe_get_uprobe(struct us_ip *ip)
-{
- return &ip->retprobe.up;
-}
-
-static int retprobe_register_probe(struct us_ip *ip)
-{
- return swap_register_uretprobe(&ip->retprobe);
-}
-
-static void retprobe_unregister_probe(struct us_ip *ip, int disarm)
-{
- __swap_unregister_uretprobe(&ip->retprobe, disarm);
-}
-
-
-static int retprobe_entry_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct uretprobe *rp = ri->rp;
-
- if (rp && get_quiet() == QT_OFF) {
- struct us_ip *ip = container_of(rp, struct us_ip, retprobe);
- const char *fmt = ip->info->rp_i.args;
- const unsigned long func_addr = (unsigned long)ip->orig_addr;
-
- rp_msg_entry(regs, func_addr, fmt);
- }
-
- return 0;
-}
-
-static int retprobe_ret_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct uretprobe *rp = ri->rp;
-
- if (rp && get_quiet() == QT_OFF) {
- struct us_ip *ip = container_of(rp, struct us_ip, retprobe);
- const unsigned long func_addr = (unsigned long)ip->orig_addr;
- const unsigned long ret_addr = (unsigned long)ri->ret_addr;
- const char ret_type = ip->info->rp_i.ret_type;
-
- rp_msg_exit(regs, func_addr, ret_type, ret_addr);
- }
-
- return 0;
-}
-
-static void retprobe_init(struct us_ip *ip)
-{
- ip->retprobe.entry_handler = retprobe_entry_handler;
- ip->retprobe.handler = retprobe_ret_handler;
- ip->retprobe.maxactive = 0;
-}
-
-static void retprobe_uninit(struct us_ip *ip)
-{
- retprobe_cleanup(ip->info);
-}
-
-
-static struct probe_iface retprobe_iface = {
- .init = retprobe_init,
- .uninit = retprobe_uninit,
- .reg = retprobe_register_probe,
- .unreg = retprobe_unregister_probe,
- .get_uprobe = retprobe_get_uprobe,
- .copy = retprobe_copy,
- .cleanup = retprobe_cleanup
-};
-
-static int __init retprobe_module_init(void)
-{
- return swap_register_probe_type(SWAP_RETPROBE, &retprobe_iface);
-}
-
-static void __exit retprobe_module_exit(void)
-{
- swap_unregister_probe_type(SWAP_RETPROBE);
-}
-
-module_init(retprobe_module_init);
-module_exit(retprobe_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP retprobe");
-MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>");
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/probes/uretprobe.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Alexander Aksenov: Probes interface implement
- *
- */
-
-#ifndef __URETPROBE_H__
-#define __URETPROBE_H__
-
-/* Common retprobe info */
-struct retprobe_info {
- char *args;
- char ret_type;
-};
-
-#endif /* __URETPROBE_H__ */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <writer/swap_msg.h>
-#include <writer/kernel_operations.h>
-#include "rp_msg.h"
-
-
-#define RP_PREFIX KERN_INFO "[RP] "
-
-
-struct msg_entry {
- u32 pid;
- u32 tid;
- u64 pc_addr;
- u64 caller_pc_addr;
- u32 cpu_num;
- u32 cnt_args;
- char args[0];
-} __packed;
-
-struct msg_exit {
- u32 pid;
- u32 tid;
- u64 pc_addr;
- u64 caller_pc_addr;
- u32 cpu_num;
- char ret_val[0];
-} __packed;
-
-
-void rp_msg_entry(struct pt_regs *regs, unsigned long func_addr,
- const char *fmt)
-{
- int ret;
- struct task_struct *task = current;
- struct swap_msg *m;
- struct msg_entry *ent;
- void *p;
- size_t size;
-
- m = swap_msg_get(MSG_FUNCTION_ENTRY);
- p = swap_msg_payload(m);
-
- ent = p;
- ent->pid = task->tgid;
- ent->tid = task->pid;
- ent->pc_addr = func_addr;
- ent->caller_pc_addr = get_regs_ret_func(regs);
- ent->cpu_num = smp_processor_id();
- ent->cnt_args = strlen(fmt);
-
- size = swap_msg_size(m);
- ret = swap_msg_pack_args(p + sizeof(*ent), size - sizeof(*ent),
- fmt, regs);
- if (ret < 0) {
- printk(RP_PREFIX "ERROR: arguments packing, ret=%d\n", ret);
- goto put_msg;
- }
-
- swap_msg_flush(m, sizeof(*ent) + ret);
-
-put_msg:
- swap_msg_put(m);
-}
-EXPORT_SYMBOL_GPL(rp_msg_entry);
-
-void rp_msg_exit(struct pt_regs *regs, unsigned long func_addr,
- char ret_type, unsigned long ret_addr)
-{
- int ret;
- struct task_struct *task = current;
- struct swap_msg *m;
- struct msg_exit *ext;
- void *p;
- size_t size;
-
- m = swap_msg_get(MSG_FUNCTION_EXIT);
- p = swap_msg_payload(m);
-
- ext = p;
- ext->pid = task->tgid;
- ext->tid = task->pid;
- ext->pc_addr = func_addr;
- ext->caller_pc_addr = ret_addr;
- ext->cpu_num = smp_processor_id();
-
- size = swap_msg_size(m);
- ret = swap_msg_pack_ret_val(p + sizeof(*ext), size - sizeof(*ext),
- ret_type, regs);
- if (ret < 0) {
- printk(RP_PREFIX "ERROR: return value packing, ret=%d\n", ret);
- goto put_msg;
- }
-
- swap_msg_flush(m, sizeof(*ext) + ret);
-
-put_msg:
- swap_msg_put(m);
-}
-EXPORT_SYMBOL_GPL(rp_msg_exit);
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _RP_MSG_H
-#define _RP_MSG_H
-
-
-struct pt_regs;
-
-
-void rp_msg_entry(struct pt_regs *regs, unsigned long func_addr,
- const char *fmt);
-void rp_msg_exit(struct pt_regs *regs, unsigned long func_addr,
- char ret_type, unsigned long ret_addr);
-
-
-#endif /* _RP_MSG_H */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_sampler.o
-swap_sampler-y := swap_sampler_module.o
-
-ifdef CONFIG_HIGH_RES_TIMERS
- swap_sampler-y += sampler_hrtimer.o
-else
- swap_sampler-y += sampler_timer.o
-endif
+++ /dev/null
-/**
- * @file sampler/kernel_operations.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Parser definitions.
- */
-
-#ifndef __KERNEL_OPERATIONS_H__
-#define __KERNEL_OPERATIONS_H__
-
-#include <linux/kernel.h>
-
-/** Prints debug message.*/
-#define print_debug(msg, args...) \
- printk(KERN_DEBUG "SWAP_SAMPLER DEBUG : " msg, ##args)
-/** Prints info message.*/
-#define print_msg(msg, args...) \
- printk(KERN_INFO "SWAP_SAMPLER : " msg, ##args)
-/** Prints warning message.*/
-#define print_warn(msg, args...) \
- printk(KERN_WARNING "SWAP_SAMPLER WARNING : " msg, ##args)
-/** Prints error message.*/
-#define print_err(msg, args...) \
- printk(KERN_ERR "SWAP_SAMPLER ERROR : " msg, ##args)
-/** Prints critical error message.*/
-#define print_crit(msg, args...) \
- printk(KERN_CRIT "SWAP_SAMPLER CRITICAL : " msg, ##args)
-
-#endif /* __KERNEL_OPERATIONS_H__ */
+++ /dev/null
-/**
- * sampler/sampler_hrtimer.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Sampler for high resolution timers.
- */
-
-
-
-#include <linux/types.h>
-#include "sampler_timers.h"
-
-
-static u64 sampler_timer_quantum;
-static DEFINE_PER_CPU(struct hrtimer, swap_hrtimer);
-static int swap_hrtimer_running;
-
-/**
- * @brief Restarts sampling.
- *
- * @param timer Pointer to hrtimer struct.
- * @return hrtimer_restart flag.
- */
-restart_ret sampler_timers_restart(swap_timer *timer)
-{
- restart_ret ret;
-
- hrtimer_forward_now(timer, ns_to_ktime(sampler_timer_quantum));
- ret = HRTIMER_RESTART;
-
- return ret;
-}
-
-/**
- * @brief Sets running flag true.
- *
- * @return Void.
- */
-void sampler_timers_set_run(void)
-{
- swap_hrtimer_running = 1;
-}
-
-/**
- * @brief Sets running flag false.
- *
- * @return Void.
- */
-void sampler_timers_set_stop(void)
-{
- swap_hrtimer_running = 0;
-}
-
-/**
- * @brief Starts timer sampling.
- *
- * @param restart_func Pointer to restart function.
- * @return Void.
- */
-void sampler_timers_start(void *restart_func)
-{
- struct hrtimer *hrtimer = &__get_cpu_var(swap_hrtimer);
-
- if (!swap_hrtimer_running)
- return;
-
- hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hrtimer->function = restart_func;
- hrtimer_start(hrtimer, ns_to_ktime(sampler_timer_quantum),
- HRTIMER_MODE_REL_PINNED);
-}
-
-/**
- * @brief Stops timer sampling.
- *
- * @param cpu Online CPUs.
- * @return Void.
- */
-void sampler_timers_stop(int cpu)
-{
- struct hrtimer *hrtimer = &per_cpu(swap_hrtimer, cpu);
-
- if (!swap_hrtimer_running)
- return;
-
- hrtimer_cancel(hrtimer);
-}
-
-/**
- * @brief Sets timer quantum.
- *
- * @param timer_quantum Timer quantum.
- * @return Void.
- */
-void sampler_timers_set_quantum(unsigned int timer_quantum)
-{
- u64 tmp = (u64)timer_quantum;
- sampler_timer_quantum = tmp * 1000 * 1000;
-}
+++ /dev/null
-/**
- * sampler/sampler_timer.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Sampler based on common timers.
- */
-
-
-
-#include "sampler_timers.h"
-
-
-
-static unsigned long sampler_timer_quantum;
-static DEFINE_PER_CPU(struct timer_list, swap_timer);
-static int swap_timer_running;
-
-/**
- * @brief Restarts sampling.
- *
- * @param timer Pointer to timer_list struct.
- * @return 0.
- */
-restart_ret sampler_timers_restart(swap_timer *timer)
-{
- restart_ret ret;
-
- mod_timer_pinned((struct timer_list *)timer,
- jiffies + sampler_timer_quantum);
- ret = 0;
-
- return ret;
-}
-
-/**
- * @brief Sets running flag true.
- *
- * @return Void.
- */
-void sampler_timers_set_run(void)
-{
- swap_timer_running = 1;
-}
-
-/**
- * @brief Sets running flag false.
- *
- * @return Void.
- */
-void sampler_timers_set_stop(void)
-{
- swap_timer_running = 0;
-}
-
-/**
- * @brief Starts timer sampling.
- *
- * @param restart_func Pointer to restart function.
- * @return Void.
- */
-void sampler_timers_start(void *restart_func)
-{
- struct timer_list *timer = &__get_cpu_var(swap_timer);
-
- if (!swap_timer_running)
- return;
-
- init_timer(timer);
- timer->data = (unsigned long)timer;
- timer->function = restart_func;
-
- mod_timer_pinned(timer, jiffies + sampler_timer_quantum);
-}
-
-/**
- * @brief Stops timer sampling.
- *
- * @param cpu Online CPUs.
- * @return Void.
- */
-void sampler_timers_stop(int cpu)
-{
- struct timer_list *timer = &per_cpu(swap_timer, cpu);
-
- if (!swap_timer_running)
- return;
- del_timer_sync(timer);
-}
-
-/**
- * @brief Sets timer quantum.
- *
- * @param timer_quantum Timer quantum.
- * @return Void.
- */
-void sampler_timers_set_quantum(unsigned int timer_quantum)
-{
- sampler_timer_quantum = timer_quantum;
-}
+++ /dev/null
-/*
- * SWAP sampler
- * modules/sampler/sampler_timers.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP sampler porting
- *
- */
-
-
-
-#ifndef __SAMPLER_TIMERS_H__
-#define __SAMPLER_TIMERS_H__
-
-
-/* ===================== INCLUDE ==================== */
-
-#if defined(CONFIG_HIGH_RES_TIMERS)
-
-#include <linux/hrtimer.h>
-
-#else /* CONFIG_HIGH_RES_TIMERS */
-
-#include <linux/timer.h>
-
-#endif /* CONFIG_HIGH_RES_TIMERS */
-
-/* ==================== TYPE DEFS =================== */
-
-#if defined(CONFIG_HIGH_RES_TIMERS)
-
-typedef struct hrtimer swap_timer;
-typedef enum hrtimer_restart restart_ret;
-
-#else /* CONFIG_HIGH_RES_TIMERS */
-
-typedef struct timer_list swap_timer;
-typedef int restart_ret;
-
-#endif /* CONFIG_HIGH_RES_TIMERS */
-
-
-/* ====================== FUNCS ===================== */
-
-restart_ret sampler_timers_restart(swap_timer *timer);
-void sampler_timers_stop(int cpu);
-void sampler_timers_start(void *unused);
-void sampler_timers_set_quantum(unsigned int timer_quantum);
-void sampler_timers_set_run(void);
-void sampler_timers_set_stop(void);
-
-#endif /* __SAMPLER_TIMERS_H__ */
+++ /dev/null
-/**
- * @file sampler/swap_sampler_errors.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Sampler error codes.
- */
-
-
-/**
- * @enum _swap_sampler_errors
- * @brief Sampler errors.
- */
-enum _swap_sampler_errors {
- E_SS_SUCCESS = 0, /**< Success. */
- E_SS_WRONG_QUANTUM = 1 /**< Wrong timer quantum set. */
-};
+++ /dev/null
-/**
- * sampler/swap_sampler_module.c
- * @author Andreev S.V.: SWAP Sampler implementation
- * @author Alexander Aksenov <a.aksenov@samsung.com>: SWAP sampler porting
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Timer-based sampling module.
- */
-
-#include <linux/ptrace.h>
-#include <linux/jiffies.h>
-#include <linux/sched.h>
-#include <linux/notifier.h>
-#include <linux/cpu.h>
-#include <linux/module.h>
-
-#include "swap_sampler_module.h"
-#include "swap_sampler_errors.h"
-#include "kernel_operations.h"
-#include "sampler_timers.h"
-
-
-static BLOCKING_NOTIFIER_HEAD(swap_sampler_notifier_list);
-static swap_sample_cb_t sampler_cb;
-
-static restart_ret swap_timer_restart(swap_timer *timer)
-{
- sampler_cb(task_pt_regs(current));
-
- return sampler_timers_restart(timer);
-}
-
-static int swap_timer_start(void)
-{
- get_online_cpus();
- sampler_timers_set_run();
-
- on_each_cpu(sampler_timers_start, swap_timer_restart, 1);
- put_online_cpus();
-
- return E_SS_SUCCESS;
-}
-
-static void swap_timer_stop(void)
-{
- int cpu;
-
- get_online_cpus();
-
- for_each_online_cpu(cpu)
- sampler_timers_stop(cpu);
- sampler_timers_set_stop();
- put_online_cpus();
-}
-
-static int __cpuinit swap_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- long cpu = (long) hcpu;
-
- switch (action) {
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- smp_call_function_single(cpu, sampler_timers_start,
- swap_timer_restart, 1);
- break;
- case CPU_DEAD:
- case CPU_DEAD_FROZEN:
- sampler_timers_stop(cpu);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block __refdata swap_cpu_notifier = {
- .notifier_call = swap_cpu_notify,
-};
-
-static int do_swap_sampler_start(unsigned int timer_quantum)
-{
- if (timer_quantum <= 0)
- return -EINVAL;
-
- sampler_timers_set_quantum(timer_quantum);
- swap_timer_start();
-
- return 0;
-}
-
-static void do_swap_sampler_stop(void)
-{
- swap_timer_stop();
-}
-
-static DEFINE_MUTEX(mutex_run);
-static int sampler_run;
-
-
-/**
- * @brief Starts sampling with specified timer quantum.
- *
- * @param timer_quantum Timer quantum for sampling.
- * @return 0 on success, error code on error.
- */
-int swap_sampler_start(unsigned int timer_quantum, swap_sample_cb_t cb)
-{
- int ret = -EINVAL;
-
- mutex_lock(&mutex_run);
- if (sampler_run) {
- printk(KERN_INFO "sampler profiling is already run!\n");
- goto unlock;
- }
-
- sampler_cb = cb;
-
- ret = do_swap_sampler_start(timer_quantum);
- if (ret == 0)
- sampler_run = 1;
-
-unlock:
- mutex_unlock(&mutex_run);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(swap_sampler_start);
-
-
-/**
- * @brief Stops sampling.
- *
- * @return 0 on success, error code on error.
- */
-int swap_sampler_stop(void)
-{
- int ret = 0;
-
- mutex_lock(&mutex_run);
- if (sampler_run == 0) {
- printk(KERN_INFO "energy profiling is not running!\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- do_swap_sampler_stop();
-
- sampler_run = 0;
-unlock:
- mutex_unlock(&mutex_run);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(swap_sampler_stop);
-
-static int __init sampler_init(void)
-{
- int retval;
-
- retval = register_hotcpu_notifier(&swap_cpu_notifier);
- if (retval) {
- print_err("Error of register_hotcpu_notifier()\n");
- return retval;
- }
-
- print_msg("Sample ininitialization success\n");
-
- return E_SS_SUCCESS;
-}
-
-static void __exit sampler_exit(void)
-{
- if (sampler_run)
- do_swap_sampler_stop();
-
- unregister_hotcpu_notifier(&swap_cpu_notifier);
-
- print_msg("Sampler uninitialized\n");
-}
-
-module_init(sampler_init);
-module_exit(sampler_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP sampling module");
-MODULE_AUTHOR("Andreev S.V., Aksenov A.S.");
+++ /dev/null
-/**
- * @file sampler/swap_sampler_module.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Sampling module interface declaration.
- */
-
-
-/* SWAP Sampler interface */
-
-#ifndef __SWAP_SAMPLER_MODULE_H__
-#define __SWAP_SAMPLER_MODULE_H__
-
-
-typedef void (*swap_sample_cb_t)(struct pt_regs *);
-
-
-/* Starts the SWAP Sampler */
-int swap_sampler_start(unsigned int timer_quantum, swap_sample_cb_t cb);
-
-/* Stops the SWAP Sampler */
-int swap_sampler_stop(void);
-
-#endif /* __SWAP_SAMPLER_MODULE_H__ */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_task_data.o
-swap_task_data-y := task_data.o
+++ /dev/null
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/stop_machine.h>
-#include <linux/slab.h>
-#include <kprobe/swap_kprobes.h>
-#include <ksyms/ksyms.h>
-#include <master/swap_initializer.h>
-#include <us_manager/callbacks.h>
-#include "task_data.h"
-
-/* lower bits are used as flags */
-#define TD_MAGIC_MASK 0xfffffff0
-#define TD_FLAGS_MASK (~TD_MAGIC_MASK)
-
-#define __DEFINE_TD_MAGIC(m) ((m) & TD_MAGIC_MASK)
-
-#define TD_MAGIC __DEFINE_TD_MAGIC(0xbebebebe)
-#define TD_OFFSET 1 /* skip STACK_END_MAGIC */
-#define TD_PREFIX "[TASK_DATA] "
-
-struct task_data {
- void *data;
- unsigned long magic;
-} __attribute__((packed));
-
-#define get_magic(td) ((td)->magic & TD_MAGIC_MASK)
-#define get_flags(td) ((td)->magic & TD_FLAGS_MASK)
-
-static int __task_data_cbs_start_h = -1;
-static int __task_data_cbs_stop_h = -1;
-
-static inline struct task_data *__td(struct task_struct *task)
-{
- return (struct task_data *)(end_of_stack(task) + TD_OFFSET);
-}
-
-static inline bool __td_check(struct task_data *td)
-{
- return (get_magic(td) == TD_MAGIC);
-}
-
-static inline void __td_init(struct task_data *td, void *data,
- unsigned long flags)
-{
- td->magic = TD_MAGIC | (flags & TD_FLAGS_MASK);
- td->data = data;
-}
-
-static inline void __td_free(struct task_data *td)
-{
- unsigned long flags = get_flags(td);
- bool ok = __td_check(td);
-
- /* freeing the data if consistency check fails is dangerous:
- * better leave it as a memory leak instead */
- if (ok) {
- if ((flags & SWAP_TD_FREE) && td->data)
- kfree(td->data);
- td->magic = 0;
- td->data = NULL;
- return;
- }
-}
-
-void *swap_task_data_get(struct task_struct *task, int *ok)
-{
- struct task_data *td = __td(task);
-
- if (ok)
- *ok = __td_check(td);
-
- return td->data;
-}
-EXPORT_SYMBOL_GPL(swap_task_data_get);
-
-void swap_task_data_set(struct task_struct *task, void *data,
- unsigned long flags)
-{
- struct task_data *td = __td(task);
-
- __td_init(td, data, flags);
-}
-EXPORT_SYMBOL_GPL(swap_task_data_set);
-
-static int copy_process_ret_handler(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct task_struct *task;
-
- task = (struct task_struct *)regs_return_value(regs);
- if (!IS_ERR(task))
- swap_task_data_clean(task);
-
- return 0;
-}
-
-static int do_exit_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct task_data *td = __td(current);
-
- __td_free(td);
-
- return 0;
-}
-
-static struct kretprobe copy_process_rp = {
- .handler = copy_process_ret_handler
-};
-
-static struct kprobe do_exit_probe = {
- .pre_handler = do_exit_handler
-};
-
-static int __set_helper_probes(void)
-{
- unsigned long addr;
- int ret;
-
- addr = swap_ksyms_substr("copy_process");
- if (addr == 0) {
- printk(TD_PREFIX "Cannot find address for copy_process\n");
- return -EINVAL;
- }
- copy_process_rp.kp.addr = (kprobe_opcode_t *)addr;
- ret = swap_register_kretprobe(©_process_rp);
- if (ret)
- goto reg_failed;
-
- addr = swap_ksyms_substr("do_exit");
- if (addr == 0) {
- printk(TD_PREFIX "Cannot find address for do_exit\n");
- return -EINVAL;
- }
- do_exit_probe.addr = (kprobe_opcode_t *)addr;
- ret = swap_register_kprobe(&do_exit_probe);
- if (ret)
- goto unreg_copy_process;
-
- return 0;
-
-unreg_copy_process:
- swap_unregister_kretprobe(©_process_rp);
-
-reg_failed:
- printk(TD_PREFIX "0x%lx: probe registration failed\n", addr);
-
- return ret;
-}
-
-static void __remove_helper_probes(void)
-{
- swap_unregister_kretprobe(©_process_rp);
- swap_unregister_kprobe(&do_exit_probe);
-}
-
-static int __task_data_init(void *data)
-{
- struct task_struct *g, *t;
-
- do_each_thread(g, t) {
- swap_task_data_clean(t);
- } while_each_thread(g, t);
-
- return 0;
-
-
-}
-
-static int __task_data_exit(void *data)
-{
- struct task_struct *g, *t;
- struct task_data *td;
-
- do_each_thread(g, t) {
- td = __td(t);
- __td_free(td);
- } while_each_thread(g, t);
-
- return 0;
-}
-
-static void task_data_start(void)
-{
- int ret;
-
- ret = __set_helper_probes();
- if (ret)
- return;
-
- /* stop_machine: cannot get tasklist_lock from module */
- ret = stop_machine(__task_data_init, NULL, NULL);
- if (ret)
- printk(TD_PREFIX "task data initialization failed: %d\n", ret);
-}
-
-static void task_data_stop(void)
-{
- int ret;
-
- __remove_helper_probes();
-
- /* stop_machine: the same here */
- ret = stop_machine(__task_data_exit, NULL, NULL);
- if (ret) {
- printk(TD_PREFIX "task data cleanup failed: %d\n", ret);
- /* something went wrong: at least make sure we unregister
- * all the installed probes */
- swap_unregister_kprobe(&do_exit_probe);
- }
-}
-
-static int task_data_init(void)
-{
- int ret = 0;
-
- __task_data_cbs_start_h = us_manager_reg_cb(START_CB, task_data_start);
-
- if (__task_data_cbs_start_h < 0) {
- ret = __task_data_cbs_start_h;
- printk(KERN_ERR TD_PREFIX "start_cb registration failed\n");
- goto out;
- }
-
- __task_data_cbs_stop_h = us_manager_reg_cb(STOP_CB_TD, task_data_stop);
-
- if (__task_data_cbs_stop_h < 0) {
- ret = __task_data_cbs_stop_h;
- us_manager_unreg_cb(__task_data_cbs_start_h);
- printk(KERN_ERR TD_PREFIX "stop_cb registration failed\n");
- }
-
-out:
- return ret;
-}
-
-static void task_data_exit(void)
-{
- us_manager_unreg_cb(__task_data_cbs_start_h);
- us_manager_unreg_cb(__task_data_cbs_stop_h);
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, task_data_init, task_data_exit, NULL, NULL);
-
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP Task Data Module");
+++ /dev/null
-#ifndef __TASK_DATA__
-#define __TASK_DATA__
-
-#define SWAP_TD_FREE 0x1 /* kfree task data automatically */
-
-struct task_struct;
-
-void *swap_task_data_get(struct task_struct *task, int *ok);
-void swap_task_data_set(struct task_struct *task, void *data,
- unsigned long flags);
-
-static inline void swap_task_data_clean(struct task_struct *task)
-{
- swap_task_data_set(task, NULL, 0);
-}
-
-#endif /* __TASK_DATA__ */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_uprobe.o
-swap_uprobe-y := swap_uprobes.o
-
-### ARM
-swap_uprobe-$(CONFIG_ARM) += arch/arm/swap-asm/swap_uprobes.o \
- arch/arm/swap-asm/trampoline_thumb.o
-
-
-### X86
-swap_uprobe-$(CONFIG_X86) += arch/x86/swap-asm/swap_uprobes.o \
- arch/x86/swap-asm/swap_sc_patch.o
+++ /dev/null
-/**
- * uprobe/arch/asm-arm/swap_uprobes.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Arch-dependent uprobe interface implementation for ARM.
- */
-
-
-#include <linux/init.h> /* need for asm/traps.h */
-#include <linux/sched.h> /* need for asm/traps.h */
-
-#include <linux/ptrace.h> /* need for asm/traps.h */
-#include <asm/traps.h>
-
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_kprobes.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <uprobe/swap_uprobes.h>
-
-#include <swap-asm/swap_kprobes.h>
-#include <swap-asm/trampoline_arm.h>
-
-#include "swap_uprobes.h"
-#include "trampoline_thumb.h"
-
-
-#define UBP_ARM (BREAKPOINT_INSTRUCTION)
-#define UBP_THUMB (BREAKPOINT_INSTRUCTION & 0xffff)
-
-/**
- * @def flush_insns
- * @brief Flushes instructions.
- */
-#define flush_insns(addr, size) \
- flush_icache_range((unsigned long)(addr), \
- (unsigned long)(addr) + (size))
-
-static inline long branch_t16_dest(kprobe_opcode_t insn, unsigned int insn_addr)
-{
- long offset = insn & 0x3ff;
- offset -= insn & 0x400;
- return insn_addr + 4 + offset * 2;
-}
-
-static inline long branch_cond_t16_dest(kprobe_opcode_t insn,
- unsigned int insn_addr)
-{
- long offset = insn & 0x7f;
- offset -= insn & 0x80;
- return insn_addr + 4 + offset * 2;
-}
-
-static inline long branch_t32_dest(kprobe_opcode_t insn, unsigned int insn_addr)
-{
- unsigned int poff = insn & 0x3ff;
- unsigned int offset = (insn & 0x07fe0000) >> 17;
-
- poff -= (insn & 0x400);
-
- if (insn & (1 << 12))
- return insn_addr + 4 + (poff << 12) + offset * 4;
- else
- return (insn_addr + 4 + (poff << 12) + offset * 4) & ~3;
-}
-
-static inline long cbz_t16_dest(kprobe_opcode_t insn, unsigned int insn_addr)
-{
- unsigned int i = (insn & 0x200) >> 3;
- unsigned int offset = (insn & 0xf8) >> 2;
- return insn_addr + 4 + i + offset;
-}
-
-/* is instruction Thumb2 and NOT a branch, etc... */
-static int is_thumb2(kprobe_opcode_t insn)
-{
- return ((insn & 0xf800) == 0xe800 ||
- (insn & 0xf800) == 0xf000 ||
- (insn & 0xf800) == 0xf800);
-}
-
-static int arch_check_insn_thumb(unsigned long insn)
-{
- int ret = 0;
-
- /* check instructions that can change PC */
- if (THUMB_INSN_MATCH(UNDEF, insn) ||
- THUMB_INSN_MATCH(SWI, insn) ||
- THUMB_INSN_MATCH(BREAK, insn) ||
- THUMB2_INSN_MATCH(B1, insn) ||
- THUMB2_INSN_MATCH(B2, insn) ||
- THUMB2_INSN_MATCH(BXJ, insn) ||
- (THUMB2_INSN_MATCH(ADR, insn) &&
- THUMB2_INSN_REG_RD(insn) == 15) ||
- (THUMB2_INSN_MATCH(LDRW, insn) && THUMB2_INSN_REG_RT(insn) == 15) ||
- (THUMB2_INSN_MATCH(LDRW1, insn) &&
- THUMB2_INSN_REG_RT(insn) == 15) ||
- (THUMB2_INSN_MATCH(LDRHW, insn) &&
- THUMB2_INSN_REG_RT(insn) == 15) ||
- (THUMB2_INSN_MATCH(LDRHW1, insn) &&
- THUMB2_INSN_REG_RT(insn) == 15) ||
- (THUMB2_INSN_MATCH(LDRWL, insn) &&
- THUMB2_INSN_REG_RT(insn) == 15) ||
- THUMB2_INSN_MATCH(LDMIA, insn) ||
- THUMB2_INSN_MATCH(LDMDB, insn) ||
- (THUMB2_INSN_MATCH(DP, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
- (THUMB2_INSN_MATCH(RSBW, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
- (THUMB2_INSN_MATCH(RORW, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
- (THUMB2_INSN_MATCH(ROR, insn) && THUMB2_INSN_REG_RD(insn) == 15) ||
- (THUMB2_INSN_MATCH(LSLW1, insn) &&
- THUMB2_INSN_REG_RD(insn) == 15) ||
- (THUMB2_INSN_MATCH(LSLW2, insn) &&
- THUMB2_INSN_REG_RD(insn) == 15) ||
- (THUMB2_INSN_MATCH(LSRW1, insn) &&
- THUMB2_INSN_REG_RD(insn) == 15) ||
- (THUMB2_INSN_MATCH(LSRW2, insn) &&
- THUMB2_INSN_REG_RD(insn) == 15) ||
- /* skip PC, #-imm12 -> SP, #-imm8 and Tegra-hanging instructions */
- (THUMB2_INSN_MATCH(STRW1, insn) &&
- THUMB2_INSN_REG_RN(insn) == 15) ||
- (THUMB2_INSN_MATCH(STRBW1, insn) &&
- THUMB2_INSN_REG_RN(insn) == 15) ||
- (THUMB2_INSN_MATCH(STRHW1, insn) &&
- THUMB2_INSN_REG_RN(insn) == 15) ||
- (THUMB2_INSN_MATCH(STRW, insn) && THUMB2_INSN_REG_RN(insn) == 15) ||
- (THUMB2_INSN_MATCH(STRHW, insn) &&
- THUMB2_INSN_REG_RN(insn) == 15) ||
- (THUMB2_INSN_MATCH(LDRW, insn) && THUMB2_INSN_REG_RN(insn) == 15) ||
- (THUMB2_INSN_MATCH(LDRBW, insn) &&
- THUMB2_INSN_REG_RN(insn) == 15) ||
- (THUMB2_INSN_MATCH(LDRHW, insn) &&
- THUMB2_INSN_REG_RN(insn) == 15) ||
- /* skip STRDx/LDRDx Rt, Rt2, [Rd, ...] */
- (THUMB2_INSN_MATCH(LDRD, insn) || THUMB2_INSN_MATCH(LDRD1, insn) ||
- THUMB2_INSN_MATCH(STRD, insn))) {
- ret = -EFAULT;
- }
-
- return ret;
-}
-
-static int prep_pc_dep_insn_execbuf_thumb(kprobe_opcode_t *insns,
- kprobe_opcode_t insn, int uregs)
-{
- unsigned char mreg = 0;
- unsigned char reg = 0;
-
- if (THUMB_INSN_MATCH(APC, insn) ||
- THUMB_INSN_MATCH(LRO3, insn)) {
- reg = ((insn & 0xffff) & uregs) >> 8;
- } else if (THUMB_INSN_MATCH(MOV3, insn)) {
- if (((((unsigned char)insn) & 0xff) >> 3) == 15)
- reg = (insn & 0xffff) & uregs;
- else
- return 0;
- } else if (THUMB2_INSN_MATCH(ADR, insn)) {
- reg = ((insn >> 16) & uregs) >> 8;
- if (reg == 15)
- return 0;
- } else if (THUMB2_INSN_MATCH(LDRW, insn) ||
- THUMB2_INSN_MATCH(LDRW1, insn) ||
- THUMB2_INSN_MATCH(LDRHW, insn) ||
- THUMB2_INSN_MATCH(LDRHW1, insn) ||
- THUMB2_INSN_MATCH(LDRWL, insn)) {
- reg = ((insn >> 16) & uregs) >> 12;
- if (reg == 15)
- return 0;
- /*
- * LDRB.W PC, [PC, #immed] => PLD [PC, #immed], so Rt == PC is skipped
- */
- } else if (THUMB2_INSN_MATCH(LDRBW, insn) ||
- THUMB2_INSN_MATCH(LDRBW1, insn) ||
- THUMB2_INSN_MATCH(LDREX, insn)) {
- reg = ((insn >> 16) & uregs) >> 12;
- } else if (THUMB2_INSN_MATCH(DP, insn)) {
- reg = ((insn >> 16) & uregs) >> 12;
- if (reg == 15)
- return 0;
- } else if (THUMB2_INSN_MATCH(RSBW, insn)) {
- reg = ((insn >> 12) & uregs) >> 8;
- if (reg == 15)
- return 0;
- } else if (THUMB2_INSN_MATCH(RORW, insn)) {
- reg = ((insn >> 12) & uregs) >> 8;
- if (reg == 15)
- return 0;
- } else if (THUMB2_INSN_MATCH(ROR, insn) ||
- THUMB2_INSN_MATCH(LSLW1, insn) ||
- THUMB2_INSN_MATCH(LSLW2, insn) ||
- THUMB2_INSN_MATCH(LSRW1, insn) ||
- THUMB2_INSN_MATCH(LSRW2, insn)) {
- reg = ((insn >> 12) & uregs) >> 8;
- if (reg == 15)
- return 0;
- } else if (THUMB2_INSN_MATCH(TEQ1, insn) ||
- THUMB2_INSN_MATCH(TST1, insn)) {
- reg = 15;
- } else if (THUMB2_INSN_MATCH(TEQ2, insn) ||
- THUMB2_INSN_MATCH(TST2, insn)) {
- reg = THUMB2_INSN_REG_RM(insn);
- }
-
- if ((THUMB2_INSN_MATCH(STRW, insn) ||
- THUMB2_INSN_MATCH(STRBW, insn) ||
- THUMB2_INSN_MATCH(STRD, insn) ||
- THUMB2_INSN_MATCH(STRHT, insn) ||
- THUMB2_INSN_MATCH(STRT, insn) ||
- THUMB2_INSN_MATCH(STRHW1, insn) ||
- THUMB2_INSN_MATCH(STRHW, insn)) &&
- THUMB2_INSN_REG_RT(insn) == 15) {
- reg = THUMB2_INSN_REG_RT(insn);
- }
-
- if (reg == 6 || reg == 7) {
- *((unsigned short *)insns + 0) =
- (*((unsigned short *)insns + 0) & 0x00ff) |
- ((1 << mreg) | (1 << (mreg + 1)));
- *((unsigned short *)insns + 1) =
- (*((unsigned short *)insns + 1) & 0xf8ff) | (mreg << 8);
- *((unsigned short *)insns + 2) =
- (*((unsigned short *)insns + 2) & 0xfff8) | (mreg + 1);
- *((unsigned short *)insns + 3) =
- (*((unsigned short *)insns + 3) & 0xffc7) | (mreg << 3);
- *((unsigned short *)insns + 7) =
- (*((unsigned short *)insns + 7) & 0xf8ff) | (mreg << 8);
- *((unsigned short *)insns + 8) =
- (*((unsigned short *)insns + 8) & 0xffc7) | (mreg << 3);
- *((unsigned short *)insns + 9) =
- (*((unsigned short *)insns + 9) & 0xffc7) |
- ((mreg + 1) << 3);
- *((unsigned short *)insns + 10) =
- (*((unsigned short *)insns + 10) & 0x00ff) |
- ((1 << mreg) | (1 << (mreg + 1)));
- }
-
- if (THUMB_INSN_MATCH(APC, insn)) {
- /* ADD Rd, PC, #immed_8*4 -> ADD Rd, SP, #immed_8*4 */
- *((unsigned short *)insns + 4) = ((insn & 0xffff) | 0x800);
- } else if (THUMB_INSN_MATCH(LRO3, insn)) {
- /* LDR Rd, [PC, #immed_8*4] ->
- * LDR Rd, [SP, #immed_8*4] */
- *((unsigned short *)insns + 4) =
- ((insn & 0xffff) + 0x5000);
- } else if (THUMB_INSN_MATCH(MOV3, insn)) {
- /* MOV Rd, PC -> MOV Rd, SP */
- *((unsigned short *)insns + 4) =
- ((insn & 0xffff) ^ 0x10);
- } else if (THUMB2_INSN_MATCH(ADR, insn)) {
- /* ADDW Rd,PC,#imm -> ADDW Rd,SP,#imm */
- insns[2] = (insn & 0xfffffff0) | 0x0d;
- } else if (THUMB2_INSN_MATCH(LDRW, insn) ||
- THUMB2_INSN_MATCH(LDRBW, insn) ||
- THUMB2_INSN_MATCH(LDRHW, insn)) {
- /* LDR.W Rt, [PC, #-<imm_12>] ->
- * LDR.W Rt, [SP, #-<imm_8>]
- * !!!!!!!!!!!!!!!!!!!!!!!!
- * !!! imm_12 vs. imm_8 !!!
- * !!!!!!!!!!!!!!!!!!!!!!!! */
- insns[2] = (insn & 0xf0fffff0) | 0x0c00000d;
- } else if (THUMB2_INSN_MATCH(LDRW1, insn) ||
- THUMB2_INSN_MATCH(LDRBW1, insn) ||
- THUMB2_INSN_MATCH(LDRHW1, insn) ||
- THUMB2_INSN_MATCH(LDRD, insn) ||
- THUMB2_INSN_MATCH(LDRD1, insn) ||
- THUMB2_INSN_MATCH(LDREX, insn)) {
- /* LDRx.W Rt, [PC, #+<imm_12>] ->
- * LDRx.W Rt, [SP, #+<imm_12>]
- (+/-imm_8 for LDRD Rt, Rt2, [PC, #<imm_8>] */
- insns[2] = (insn & 0xfffffff0) | 0xd;
- } else if (THUMB2_INSN_MATCH(MUL, insn)) {
- /* MUL Rd, Rn, SP */
- insns[2] = (insn & 0xfff0ffff) | 0x000d0000;
- } else if (THUMB2_INSN_MATCH(DP, insn)) {
- if (THUMB2_INSN_REG_RM(insn) == 15)
- /* DP Rd, Rn, PC */
- insns[2] = (insn & 0xfff0ffff) | 0x000d0000;
- else if (THUMB2_INSN_REG_RN(insn) == 15)
- /* DP Rd, PC, Rm */
- insns[2] = (insn & 0xfffffff0) | 0xd;
- } else if (THUMB2_INSN_MATCH(LDRWL, insn)) {
- /* LDRx.W Rt, [PC, #<imm_12>] ->
- * LDRx.W Rt, [SP, #+<imm_12>]
- * (+/-imm_8 for LDRD Rt, Rt2, [PC, #<imm_8>] */
- insns[2] = (insn & 0xfffffff0) | 0xd;
- } else if (THUMB2_INSN_MATCH(RSBW, insn)) {
- /* RSB{S}.W Rd, PC, #<const> -> RSB{S}.W Rd, SP, #<const> */
- insns[2] = (insn & 0xfffffff0) | 0xd;
- } else if (THUMB2_INSN_MATCH(RORW, insn) ||
- THUMB2_INSN_MATCH(LSLW1, insn) ||
- THUMB2_INSN_MATCH(LSRW1, insn)) {
- if ((THUMB2_INSN_REG_RM(insn) == 15) &&
- (THUMB2_INSN_REG_RN(insn) == 15))
- /* ROR.W Rd, PC, PC */
- insns[2] = (insn & 0xfffdfffd);
- else if (THUMB2_INSN_REG_RM(insn) == 15)
- /* ROR.W Rd, Rn, PC */
- insns[2] = (insn & 0xfff0ffff) | 0xd0000;
- else if (THUMB2_INSN_REG_RN(insn) == 15)
- /* ROR.W Rd, PC, Rm */
- insns[2] = (insn & 0xfffffff0) | 0xd;
- } else if (THUMB2_INSN_MATCH(ROR, insn) ||
- THUMB2_INSN_MATCH(LSLW2, insn) ||
- THUMB2_INSN_MATCH(LSRW2, insn)) {
- /* ROR{S} Rd, PC, #<const> -> ROR{S} Rd, SP, #<const> */
- insns[2] = (insn & 0xfff0ffff) | 0xd0000;
- }
-
- if (THUMB2_INSN_MATCH(STRW, insn) ||
- THUMB2_INSN_MATCH(STRBW, insn)) {
- /* STRx.W Rt, [Rn, SP] */
- insns[2] = (insn & 0xfff0ffff) | 0x000d0000;
- } else if (THUMB2_INSN_MATCH(STRD, insn) ||
- THUMB2_INSN_MATCH(STRHT, insn) ||
- THUMB2_INSN_MATCH(STRT, insn) ||
- THUMB2_INSN_MATCH(STRHW1, insn)) {
- if (THUMB2_INSN_REG_RN(insn) == 15)
- /* STRD/T/HT{.W} Rt, [SP, ...] */
- insns[2] = (insn & 0xfffffff0) | 0xd;
- else
- insns[2] = insn;
- } else if (THUMB2_INSN_MATCH(STRHW, insn) &&
- (THUMB2_INSN_REG_RN(insn) == 15)) {
- if (THUMB2_INSN_REG_RN(insn) == 15)
- /* STRH.W Rt, [SP, #-<imm_8>] */
- insns[2] = (insn & 0xf0fffff0) | 0x0c00000d;
- else
- insns[2] = insn;
- }
-
- /* STRx PC, xxx */
- if ((reg == 15) && (THUMB2_INSN_MATCH(STRW, insn) ||
- THUMB2_INSN_MATCH(STRBW, insn) ||
- THUMB2_INSN_MATCH(STRD, insn) ||
- THUMB2_INSN_MATCH(STRHT, insn) ||
- THUMB2_INSN_MATCH(STRT, insn) ||
- THUMB2_INSN_MATCH(STRHW1, insn) ||
- THUMB2_INSN_MATCH(STRHW, insn))) {
- insns[2] = (insns[2] & 0x0fffffff) | 0xd0000000;
- }
-
- if (THUMB2_INSN_MATCH(TEQ1, insn) ||
- THUMB2_INSN_MATCH(TST1, insn)) {
- /* TEQ SP, #<const> */
- insns[2] = (insn & 0xfffffff0) | 0xd;
- } else if (THUMB2_INSN_MATCH(TEQ2, insn) ||
- THUMB2_INSN_MATCH(TST2, insn)) {
- if ((THUMB2_INSN_REG_RN(insn) == 15) &&
- (THUMB2_INSN_REG_RM(insn) == 15))
- /* TEQ/TST PC, PC */
- insns[2] = (insn & 0xfffdfffd);
- else if (THUMB2_INSN_REG_RM(insn) == 15)
- /* TEQ/TST Rn, PC */
- insns[2] = (insn & 0xfff0ffff) | 0xd0000;
- else if (THUMB2_INSN_REG_RN(insn) == 15)
- /* TEQ/TST PC, Rm */
- insns[2] = (insn & 0xfffffff0) | 0xd;
- }
-
- return 0;
-}
-
-static int arch_make_trampoline_thumb(unsigned long vaddr, unsigned long insn,
- unsigned long *tramp, size_t tramp_len)
-{
- int ret;
- int uregs = 0;
- int pc_dep = 0;
- unsigned int addr;
-
- ret = arch_check_insn_thumb(insn);
- if (ret) {
- pr_err("THUMB inst isn't support vaddr=%lx insn=%08lx\n",
- vaddr, insn);
- return ret;
- }
-
- if (THUMB_INSN_MATCH(APC, insn) || THUMB_INSN_MATCH(LRO3, insn)) {
- uregs = 0x0700; /* 8-10 */
- pc_dep = 1;
- } else if (THUMB_INSN_MATCH(MOV3, insn) &&
- (((((unsigned char)insn) & 0xff) >> 3) == 15)) {
- /* MOV Rd, PC */
- uregs = 0x07;
- pc_dep = 1;
- } else if THUMB2_INSN_MATCH(ADR, insn) {
- uregs = 0x0f00; /* Rd 8-11 */
- pc_dep = 1;
- } else if (((THUMB2_INSN_MATCH(LDRW, insn) ||
- THUMB2_INSN_MATCH(LDRW1, insn) ||
- THUMB2_INSN_MATCH(LDRBW, insn) ||
- THUMB2_INSN_MATCH(LDRBW1, insn) ||
- THUMB2_INSN_MATCH(LDRHW, insn) ||
- THUMB2_INSN_MATCH(LDRHW1, insn) ||
- THUMB2_INSN_MATCH(LDRWL, insn)) &&
- THUMB2_INSN_REG_RN(insn) == 15) ||
- THUMB2_INSN_MATCH(LDREX, insn) ||
- ((THUMB2_INSN_MATCH(STRW, insn) ||
- THUMB2_INSN_MATCH(STRBW, insn) ||
- THUMB2_INSN_MATCH(STRHW, insn) ||
- THUMB2_INSN_MATCH(STRHW1, insn)) &&
- (THUMB2_INSN_REG_RN(insn) == 15 ||
- THUMB2_INSN_REG_RT(insn) == 15)) ||
- ((THUMB2_INSN_MATCH(STRT, insn) ||
- THUMB2_INSN_MATCH(STRHT, insn)) &&
- (THUMB2_INSN_REG_RN(insn) == 15 ||
- THUMB2_INSN_REG_RT(insn) == 15))) {
- uregs = 0xf000; /* Rt 12-15 */
- pc_dep = 1;
- } else if ((THUMB2_INSN_MATCH(LDRD, insn) ||
- THUMB2_INSN_MATCH(LDRD1, insn)) &&
- (THUMB2_INSN_REG_RN(insn) == 15)) {
- uregs = 0xff00; /* Rt 12-15, Rt2 8-11 */
- pc_dep = 1;
- } else if (THUMB2_INSN_MATCH(MUL, insn) &&
- THUMB2_INSN_REG_RM(insn) == 15) {
- uregs = 0xf;
- pc_dep = 1;
- } else if (THUMB2_INSN_MATCH(DP, insn) &&
- (THUMB2_INSN_REG_RN(insn) == 15 ||
- THUMB2_INSN_REG_RM(insn) == 15)) {
- uregs = 0xf000; /* Rd 12-15 */
- pc_dep = 1;
- } else if (THUMB2_INSN_MATCH(STRD, insn) &&
- ((THUMB2_INSN_REG_RN(insn) == 15) ||
- (THUMB2_INSN_REG_RT(insn) == 15) ||
- THUMB2_INSN_REG_RT2(insn) == 15)) {
- uregs = 0xff00; /* Rt 12-15, Rt2 8-11 */
- pc_dep = 1;
- } else if (THUMB2_INSN_MATCH(RSBW, insn) &&
- THUMB2_INSN_REG_RN(insn) == 15) {
- uregs = 0x0f00; /* Rd 8-11 */
- pc_dep = 1;
- } else if (THUMB2_INSN_MATCH(RORW, insn) &&
- (THUMB2_INSN_REG_RN(insn) == 15 ||
- THUMB2_INSN_REG_RM(insn) == 15)) {
- uregs = 0x0f00;
- pc_dep = 1;
- } else if ((THUMB2_INSN_MATCH(ROR, insn) ||
- THUMB2_INSN_MATCH(LSLW2, insn) ||
- THUMB2_INSN_MATCH(LSRW2, insn)) &&
- THUMB2_INSN_REG_RM(insn) == 15) {
- uregs = 0x0f00; /* Rd 8-11 */
- pc_dep = 1;
- } else if ((THUMB2_INSN_MATCH(LSLW1, insn) ||
- THUMB2_INSN_MATCH(LSRW1, insn)) &&
- (THUMB2_INSN_REG_RN(insn) == 15 ||
- THUMB2_INSN_REG_RM(insn) == 15)) {
- uregs = 0x0f00; /* Rd 8-11 */
- pc_dep = 1;
- } else if ((THUMB2_INSN_MATCH(TEQ1, insn) ||
- THUMB2_INSN_MATCH(TST1, insn)) &&
- THUMB2_INSN_REG_RN(insn) == 15) {
- uregs = 0xf0000; /* Rn 0-3 (16-19) */
- pc_dep = 1;
- } else if ((THUMB2_INSN_MATCH(TEQ2, insn) ||
- THUMB2_INSN_MATCH(TST2, insn)) &&
- (THUMB2_INSN_REG_RN(insn) == 15 ||
- THUMB2_INSN_REG_RM(insn) == 15)) {
- uregs = 0xf0000; /* Rn 0-3 (16-19) */
- pc_dep = 1;
- }
-
- if (unlikely(uregs && pc_dep)) {
- memcpy(tramp, pc_dep_insn_execbuf_thumb, tramp_len);
- prep_pc_dep_insn_execbuf_thumb(tramp, insn, uregs);
-
- addr = vaddr + 4;
- *((unsigned short *)tramp + 13) = 0xdeff;
- *((unsigned short *)tramp + 14) = addr & 0x0000ffff;
- *((unsigned short *)tramp + 15) = addr >> 16;
- if (!is_thumb2(insn)) {
- addr = vaddr + 2;
- *((unsigned short *)tramp + 16) =
- (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
- } else {
- addr = vaddr + 4;
- *((unsigned short *)tramp + 16) =
- (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
- }
- } else {
- memcpy(tramp, gen_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
- if (!is_thumb2(insn)) {
- addr = vaddr + 2;
- *((unsigned short *)tramp + 2) = insn;
- *((unsigned short *)tramp + 16) =
- (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
- } else {
- addr = vaddr + 4;
- tramp[1] = insn;
- *((unsigned short *)tramp + 16) =
- (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
- }
- }
-
- if (THUMB_INSN_MATCH(B2, insn)) {
- memcpy(tramp, b_off_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
- addr = branch_t16_dest(insn, vaddr);
- *((unsigned short *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 15) = addr >> 16;
- *((unsigned short *)tramp + 16) = 0;
- *((unsigned short *)tramp + 17) = 0;
-
- } else if (THUMB_INSN_MATCH(B1, insn)) {
- memcpy(tramp, b_cond_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
- *((unsigned short *)tramp + 0) |= (insn & 0xf00);
- addr = branch_cond_t16_dest(insn, vaddr);
- *((unsigned short *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 15) = addr >> 16;
- addr = vaddr + 2;
- *((unsigned short *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
-
- } else if (THUMB_INSN_MATCH(BLX2, insn) ||
- THUMB_INSN_MATCH(BX, insn)) {
- memcpy(tramp, b_r_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
- *((unsigned short *)tramp + 4) = insn;
- addr = vaddr + 2;
- *((unsigned short *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
-
- } else if (THUMB2_INSN_MATCH(BLX1, insn) ||
- THUMB2_INSN_MATCH(BL, insn)) {
- memcpy(tramp, blx_off_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
- addr = branch_t32_dest(insn, vaddr);
- *((unsigned short *)tramp + 14) = (addr & 0x0000ffff);
- *((unsigned short *)tramp + 15) = addr >> 16;
- addr = vaddr + 4;
- *((unsigned short *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
-
- } else if (THUMB_INSN_MATCH(CBZ, insn)) {
- memcpy(tramp, cbz_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
- /* zero out original branch displacement (imm5 = 0; i = 0) */
- *((unsigned short *)tramp + 0) = insn & (~0x2f8);
- /* replace it with 8 bytes offset in execbuf (imm5 = 0b00010) */
- *((unsigned short *)tramp + 0) |= 0x20;
- addr = cbz_t16_dest(insn, vaddr);
- *((unsigned short *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 15) = addr >> 16;
- addr = vaddr + 2;
- *((unsigned short *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
- }
-
- return 0;
-}
-
-/**
- * @brief Prepares uprobe for ARM.
- *
- * @param up Pointer to the uprobe.
- * @return 0 on success,\n
- * negative error code on error.
- */
-int arch_prepare_uprobe(struct uprobe *up)
-{
- int ret;
- struct kprobe *p = up2kp(up);
- struct task_struct *task = up->task;
- unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
- unsigned long insn;
- int thumb_mode = (unsigned long)p->addr & 1;
- unsigned long tramp[UPROBES_TRAMP_LEN];
- unsigned long __user *utramp;
- enum { tramp_len = sizeof(tramp) };
-
- if (!read_proc_vm_atomic(task, vaddr, &insn, sizeof(insn))) {
- printk(KERN_ERR "failed to read memory %lx!\n", vaddr);
- return -EINVAL;
- }
-
- ret = thumb_mode ?
- arch_make_trampoline_thumb(vaddr, insn,
- tramp, tramp_len) :
- arch_make_trampoline_arm(vaddr, insn, tramp);
- if (ret) {
- pr_err("failed to make tramp, addr=%p\n", p->addr);
- return ret;
- }
-
- utramp = swap_slot_alloc(up->sm);
- if (utramp == NULL) {
- printk(KERN_INFO "Error: swap_slot_alloc failed (%08lx)\n",
- vaddr);
- return -ENOMEM;
- }
-
- if (!write_proc_vm_atomic(up->task, (unsigned long)utramp, tramp,
- tramp_len)) {
- pr_err("failed to write memory tramp=%p!\n", utramp);
- swap_slot_free(up->sm, utramp);
- return -EINVAL;
- }
-
- flush_insns(utramp, tramp_len);
- p->ainsn.insn = utramp;
- p->opcode = insn;
-
- /* for uretprobe */
- add_uprobe_table(p);
-
- return 0;
-}
-
-/**
- * @brief Analysis opcodes.
- *
- * @param rp Pointer to the uretprobe.
- * @return Void.
- */
-void arch_opcode_analysis_uretprobe(struct uretprobe *rp)
-{
- /* Remove retprobe if first insn overwrites lr */
- rp->thumb_noret = !!(THUMB2_INSN_MATCH(BL, rp->up.kp.opcode) ||
- THUMB2_INSN_MATCH(BLX1, rp->up.kp.opcode) ||
- THUMB_INSN_MATCH(BLX2, rp->up.kp.opcode));
-
- rp->arm_noret = !!(ARM_INSN_MATCH(BL, rp->up.kp.opcode) ||
- ARM_INSN_MATCH(BLX1, rp->up.kp.opcode) ||
- ARM_INSN_MATCH(BLX2, rp->up.kp.opcode));
-}
-
-/**
- * @brief Prepates uretprobe for ARM.
- *
- * @param ri Pointer to the uretprobe instance.
- * @param regs Pointer to CPU register data.
- * @return Error code.
- */
-int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr;
- ri->sp = (kprobe_opcode_t *)regs->ARM_sp;
-
- /* Set flag of current mode */
- ri->sp = (kprobe_opcode_t *)((long)ri->sp | !!thumb_mode(regs));
-
- if (ri->preload_thumb) {
- regs->ARM_lr = (unsigned long)(ri->rp->up.kp.ainsn.insn) + 0x1b;
- } else {
- if (thumb_mode(regs))
- regs->ARM_lr = (unsigned long)(ri->rp->up.kp.ainsn.insn) + 0x1b;
- else
- regs->ARM_lr = (unsigned long)(ri->rp->up.kp.ainsn.insn +
- UPROBES_TRAMP_RET_BREAK_IDX);
- }
-
- return 0;
-}
-
-unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
-{
- /* Understand function mode */
- return ((unsigned long)ri->sp & 1) ?
- ((unsigned long)ri->rp->up.kp.ainsn.insn + 0x1b) :
- (unsigned long)(ri->rp->up.kp.ainsn.insn +
- UPROBES_TRAMP_RET_BREAK_IDX);
-}
-
-/**
- * @brief Disarms uretprobe instance.
- *
- * @param ri Pointer to the uretprobe instance
- * @param task Pointer to the task for which the uretprobe instance
- * @return 0 on success,\n
- * negative error code on error.
- */
-int arch_disarm_urp_inst(struct uretprobe_instance *ri,
- struct task_struct *task, unsigned long tr)
-{
- struct pt_regs *uregs = task_pt_regs(ri->task);
- unsigned long ra = swap_get_ret_addr(uregs);
- unsigned long *tramp;
- unsigned long *sp = (unsigned long *)((long)ri->sp & ~1);
- unsigned long *stack = sp - RETPROBE_STACK_DEPTH + 1;
- unsigned long *found = NULL;
- unsigned long *buf[RETPROBE_STACK_DEPTH];
- unsigned long vaddr;
- int i, retval;
-
- if (tr == 0) {
- vaddr = (unsigned long)ri->rp->up.kp.addr;
- tramp = (unsigned long *)arch_tramp_by_ri(ri);
- } else {
- /* ri - invalid */
- vaddr = 0;
- tramp = (unsigned long *)tr;
- }
-
- /* check stack */
- retval = read_proc_vm_atomic(task, (unsigned long)stack,
- buf, sizeof(buf));
- if (retval != sizeof(buf)) {
- printk(KERN_INFO "---> %s (%d/%d): failed to read "
- "stack from %08lx\n", task->comm, task->tgid, task->pid,
- (unsigned long)stack);
- retval = -EFAULT;
- goto check_lr;
- }
-
- /* search the stack from the bottom */
- for (i = RETPROBE_STACK_DEPTH - 1; i >= 0; i--) {
- if (buf[i] == tramp) {
- found = stack + i;
- break;
- }
- }
-
- if (!found) {
- retval = -ESRCH;
- goto check_lr;
- }
-
- printk(KERN_INFO "---> %s (%d/%d): trampoline found at "
- "%08lx (%08lx /%+d) - %lx, set ret_addr=%p\n",
- task->comm, task->tgid, task->pid,
- (unsigned long)found, (unsigned long)sp,
- found - sp, vaddr, ri->ret_addr);
- retval = write_proc_vm_atomic(task, (unsigned long)found,
- &ri->ret_addr,
- sizeof(ri->ret_addr));
- if (retval != sizeof(ri->ret_addr)) {
- printk(KERN_INFO "---> %s (%d/%d): "
- "failed to write value to %08lx",
- task->comm, task->tgid, task->pid, (unsigned long)found);
- retval = -EFAULT;
- } else {
- retval = 0;
- }
-
-check_lr: /* check lr anyway */
- if (ra == (unsigned long)tramp) {
- printk(KERN_INFO "---> %s (%d/%d): trampoline found at "
- "lr = %08lx - %lx, set ret_addr=%p\n",
- task->comm, task->tgid, task->pid, ra, vaddr, ri->ret_addr);
-
- swap_set_ret_addr(uregs, (unsigned long)ri->ret_addr);
- retval = 0;
- } else if (retval) {
- printk(KERN_INFO "---> %s (%d/%d): trampoline NOT found at "
- "sp = %08lx, lr = %08lx - %lx, ret_addr=%p\n",
- task->comm, task->tgid, task->pid,
- (unsigned long)sp, ra, vaddr, ri->ret_addr);
- }
-
- return retval;
-}
-
-/**
- * @brief Jump pre-handler.
- *
- * @param p Pointer to the kprobe.
- * @param regs Pointer to CPU register data.
- * @return 0.
- */
-int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct uprobe *up = container_of(p, struct uprobe, kp);
- struct ujprobe *jp = container_of(up, struct ujprobe, up);
-
- kprobe_pre_entry_handler_t pre_entry =
- (kprobe_pre_entry_handler_t)jp->pre_entry;
- entry_point_t entry = (entry_point_t)jp->entry;
-
- if (pre_entry) {
- p->ss_addr[smp_processor_id()] = (kprobe_opcode_t *)
- pre_entry(jp->priv_arg, regs);
- }
-
- if (entry) {
- entry(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
- regs->ARM_r3, regs->ARM_r4, regs->ARM_r5);
- } else {
- arch_ujprobe_return();
- }
-
- return 0;
-}
-
-/**
- * @brief Gets trampoline address.
- *
- * @param p Pointer to the kprobe.
- * @param regs Pointer to CPU register data.
- * @return Trampoline address.
- */
-unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs)
-{
- return thumb_mode(regs) ?
- (unsigned long)(p->ainsn.insn) + 0x1b :
- (unsigned long)(p->ainsn.insn +
- UPROBES_TRAMP_RET_BREAK_IDX);
-}
-
-/**
- * @brief Restores return address.
- *
- * @param orig_ret_addr Original return address.
- * @param regs Pointer to CPU register data.
- * @return Void.
- */
-void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
-{
- regs->ARM_lr = orig_ret_addr;
- regs->ARM_pc = orig_ret_addr & ~0x1;
-
- if (regs->ARM_lr & 0x1)
- regs->ARM_cpsr |= PSR_T_BIT;
- else
- regs->ARM_cpsr &= ~PSR_T_BIT;
-}
-
-/**
- * @brief Removes uprobe.
- *
- * @param up Pointer to the uprobe.
- * @return Void.
- */
-void arch_remove_uprobe(struct uprobe *up)
-{
- swap_slot_free(up->sm, up->kp.ainsn.insn);
-}
-
-int arch_arm_uprobe(struct uprobe *p)
-{
- int ret;
- unsigned long vaddr = (unsigned long)p->kp.addr & ~((unsigned long)1);
- int thumb_mode = (unsigned long)p->kp.addr & 1;
- int len = 4 >> thumb_mode; /* if thumb_mode then len = 2 */
- unsigned long insn = thumb_mode ? UBP_THUMB : UBP_ARM;
-
- ret = write_proc_vm_atomic(p->task, vaddr, &insn, len);
- if (!ret) {
- pr_err("arch_arm_uprobe: failed to write memory tgid=%u addr=%08lx len=%d\n",
- p->task->tgid, vaddr, len);
-
- return -EACCES;
- } else {
- flush_insns(vaddr, len);
- }
-
- return 0;
-}
-
-void arch_disarm_uprobe(struct kprobe *p, struct task_struct *task)
-{
- int ret;
-
- unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
- int thumb_mode = (unsigned long)p->addr & 1;
- int len = 4 >> thumb_mode; /* if thumb_mode then len = 2 */
-
- ret = write_proc_vm_atomic(task, vaddr, &p->opcode, len);
- if (!ret) {
- pr_err("arch_disarm_uprobe: failed to write memory tgid=%u addr=%08lx len=%d\n",
- task->tgid, vaddr, len);
- } else {
- flush_insns(vaddr, len);
- }
-}
-
-static int urp_handler(struct pt_regs *regs, pid_t tgid)
-{
- struct kprobe *p;
- unsigned long vaddr = regs->ARM_pc;
- unsigned long offset_bp = thumb_mode(regs) ?
- 0x1a :
- 4 * UPROBES_TRAMP_RET_BREAK_IDX;
- unsigned long tramp_addr = vaddr - offset_bp;
-
- p = get_ukprobe_by_insn_slot((void *)tramp_addr, tgid, regs);
- if (p == NULL) {
- printk(KERN_INFO
- "no_uprobe: Not one of ours: let kernel handle it %lx\n",
- vaddr);
- return 1;
- }
-
- trampoline_uprobe_handler(p, regs);
-
- return 0;
-}
-
-/**
- * @brief Breakpoint instruction handler.
- *
- * @param regs Pointer to CPU register data.
- * @param instr Instruction.
- * @return uprobe_handler results.
- */
-int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
-{
- int ret = 0;
- struct kprobe *p;
- unsigned long flags;
- unsigned long vaddr = regs->ARM_pc | !!thumb_mode(regs);
- pid_t tgid = current->tgid;
-
- local_irq_save(flags);
- preempt_disable();
-
- p = get_ukprobe((kprobe_opcode_t *)vaddr, tgid);
- if (p) {
- struct uprobe *up = kp2up(p);
- bool prepare = false;
-
- if (up->atomic_ctx) {
- if (!p->pre_handler || !p->pre_handler(p, regs))
- prepare = true;
- } else {
- swap_preempt_enable_no_resched();
- local_irq_restore(flags);
-
- if (!p->pre_handler || !p->pre_handler(p, regs))
- prepare = true;
-
- local_irq_save(flags);
- preempt_disable();
- }
-
- if (prepare)
- prepare_singlestep(p, regs);
- } else {
- ret = urp_handler(regs, tgid);
-
- /* check ARM/THUMB mode on correct */
- if (ret) {
- vaddr ^= 1;
- p = get_ukprobe((kprobe_opcode_t *)vaddr, tgid);
- if (p) {
- pr_err("invalid mode: thumb=%d addr=%p insn=%08lx\n",
- !!thumb_mode(regs), p->addr, p->opcode);
- ret = 0;
-
- swap_preempt_enable_no_resched();
- local_irq_restore(flags);
-
- disarm_uprobe(p, current);
-
- local_irq_save(flags);
- preempt_disable();
- }
- }
- }
-
- swap_preempt_enable_no_resched();
- local_irq_restore(flags);
-
- return ret;
-}
-
-/* userspace probes hook (arm) */
-static struct undef_hook undef_hook_for_us_arm = {
- .instr_mask = 0xffffffff,
- .instr_val = UBP_ARM,
- .cpsr_mask = MODE_MASK,
- .cpsr_val = USR_MODE,
- .fn = uprobe_trap_handler
-};
-
-/* userspace probes hook (thumb) */
-static struct undef_hook undef_hook_for_us_thumb = {
- .instr_mask = 0xffffffff,
- .instr_val = UBP_THUMB,
- .cpsr_mask = MODE_MASK,
- .cpsr_val = USR_MODE,
- .fn = uprobe_trap_handler
-};
-
-/**
- * @brief Installs breakpoint hooks.
- *
- * @return 0.
- */
-int swap_arch_init_uprobes(void)
-{
- swap_register_undef_hook(&undef_hook_for_us_arm);
- swap_register_undef_hook(&undef_hook_for_us_thumb);
-
- return 0;
-}
-
-/**
- * @brief Uninstalls breakpoint hooks.
- *
- * @return Void.
- */
-void swap_arch_exit_uprobes(void)
-{
- swap_unregister_undef_hook(&undef_hook_for_us_thumb);
- swap_unregister_undef_hook(&undef_hook_for_us_arm);
-}
+++ /dev/null
-/**
- * @file uprobe/arch/asm-arm/swap_uprobes.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Arch-dependent uprobe interface declaration.
- */
-
-
-#ifndef _ARM_SWAP_UPROBES_H
-#define _ARM_SWAP_UPROBES_H
-
-
-#include <linux/uaccess.h>
-#include <swap-asm/swap_kprobes.h> /* FIXME: for UPROBES_TRAMP_LEN */
-
-
-struct kprobe;
-struct task_struct;
-struct uprobe;
-struct uretprobe;
-struct uretprobe_instance;
-
-/**
- * @struct arch_specific_tramp
- * @brief Stores arch-dependent trampolines.
- */
-struct arch_specific_tramp {
-};
-
-
-static inline u32 swap_get_urp_float(struct pt_regs *regs)
-{
- return regs->ARM_r0;
-}
-
-static inline u64 swap_get_urp_double(struct pt_regs *regs)
-{
-
- return regs->ARM_r0 | (u64)regs->ARM_r1 << 32;
-}
-
-static inline void arch_ujprobe_return(void)
-{
-}
-
-int arch_prepare_uprobe(struct uprobe *up);
-
-int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs);
-static inline int longjmp_break_uhandler(struct kprobe *p, struct pt_regs *regs)
-{
- return 0;
-}
-
-void arch_opcode_analysis_uretprobe(struct uretprobe *rp);
-int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
-int arch_disarm_urp_inst(struct uretprobe_instance *ri,
- struct task_struct *task, unsigned long tr);
-unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri);
-
-unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
-void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
-void arch_remove_uprobe(struct uprobe *up);
-int arch_arm_uprobe(struct uprobe *p);
-void arch_disarm_uprobe(struct kprobe *p, struct task_struct *task);
-
-static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
-{
- u32 *ptr, addr = 0;
-
- switch (n) {
- case 0:
- return regs->ARM_r0;
- case 1:
- return regs->ARM_r1;
- case 2:
- return regs->ARM_r2;
- case 3:
- return regs->ARM_r3;
- }
-
- ptr = (u32 *)regs->ARM_sp + n - 4;
- if (get_user(addr, ptr))
- printk(KERN_INFO "failed to dereference a pointer, ptr=%p\n",
- ptr);
-
- return addr;
-}
-
-static inline void swap_put_uarg(struct pt_regs *regs, unsigned long n,
- unsigned long val)
-{
- u32 *ptr;
-
- switch (n) {
- case 0:
- regs->ARM_r0 = val;
- break;
- case 1:
- regs->ARM_r1 = val;
- break;
- case 2:
- regs->ARM_r2 = val;
- break;
- case 3:
- regs->ARM_r3 = val;
- break;
- default:
- ptr = (u32 *)regs->ARM_sp + n - 4;
- if (put_user(val, ptr))
- pr_err("failed to dereference a pointer[%p]\n", ptr);
- }
-}
-
-int swap_arch_init_uprobes(void);
-void swap_arch_exit_uprobes(void);
-
-#endif /* _ARM_SWAP_UPROBES_H */
+++ /dev/null
- .thumb
-
- .global gen_insn_execbuf_thumb
-gen_insn_execbuf_thumb:
- nop
- nop
- nop // original instruction
- nop // original instruction
- nop
- nop
- nop
- sub sp, sp, #8
- str r0, [sp, #0]
- ldr r0, [pc, #12]
- str r0, [sp, #4]
- nop
- pop {r0, pc} // ssbreak
- nop // retbreak
- nop
- nop
- nop // stored PC-4(next insn addr) hi
- nop // stored PC-4(next insn addr) lo
-
- nop
-
- .global pc_dep_insn_execbuf_thumb
- .align 4
-pc_dep_insn_execbuf_thumb:
- push {r6, r7}
- ldr r6, i1
- mov r7, sp
- mov sp, r6
- nop // PC -> SP
- nop // PC -> SP
- mov sp, r7
- pop {r6, r7}
- push {r0, r1}
- ldr r0, i2
- nop
- str r0, [sp, #4]
- pop {r0, pc} // ssbreak
- nop // retbreak
-i1: nop // stored PC hi
- nop // stored PC lo
-i2: nop // stored PC-4(next insn addr) hi
- nop // stored PC-4(next insn addr) lo
-
- .global b_r_insn_execbuf_thumb
- .align 4
-b_r_insn_execbuf_thumb:
- nop
- nop
- nop
- nop
- nop // bx,blx (Rm)
- nop //
- push {r0,r1}
- ldr r0, np
- nop
- str r0, [sp, #4]
- pop {r0,pc}
- nop
- nop // ssbreak
- nop // retbreak
- nop
- nop
-np: nop // stored PC-4(next insn addr) hi
- nop // stored PC-4(next insn addr) lo
-
- .global b_off_insn_execbuf_thumb
- .align 4
-b_off_insn_execbuf_thumb:
- push {r0,r1}
- ldr r0, bd
- str r0, [sp, #4]
- pop {r0, pc}
- nop
- nop
- push {r0,r1}
- ldr r0, np2
- nop
- str r0, [sp, #4]
- pop {r0,pc}
- nop
- nop // ssbreak
- nop // retbreak
-bd: nop // branch displacement hi
- nop // branch displacement lo
-np2: nop // stored PC-4(next insn addr) hi
- nop // stored PC-4(next insn addr) lo
-
- .global blx_off_insn_execbuf_thumb
- .align 4
-blx_off_insn_execbuf_thumb:
- push {r0}
- ldr r0, bd3
- mov lr, r0
- pop {r0}
- blx lr
- nop
- push {r0,r1}
- ldr r0, np3
- nop
- str r0, [sp, #4]
- pop {r0,pc}
- nop
- nop // ssbreak
- nop // retbreak
-bd3: nop // branch displacement hi
- nop // branch displacement lo
-np3: nop // stored PC-4(next insn addr) hi
- nop // stored PC-4(next insn addr) lo
-
- .global b_cond_insn_execbuf_thumb
- .align 4
-b_cond_insn_execbuf_thumb:
- beq condway
- push {r0,r1}
- ldr r0, np4
- nop
- str r0, [sp, #4]
- pop {r0,pc}
-condway: push {r0,r1}
- ldr r0, bd4
- str r0, [sp, #4]
- pop {r0,pc}
- nop
- nop
- nop // ssbreak
- nop // retbreak
-bd4: nop // branch displacement hi
- nop // branch displacement lo
-np4: nop // stored PC-4(next insn addr) hi
- nop // stored PC-4(next insn addr) lo
-
- .global cbz_insn_execbuf_thumb
- .align 4
-cbz_insn_execbuf_thumb:
- nop // cbz
- push {r0,r1}
- ldr r0, np5
- nop
- str r0, [sp, #4]
- pop {r0,pc}
- push {r0,r1}
- ldr r0, bd5
- str r0, [sp, #4]
- pop {r0,pc}
- nop
- nop
- nop // ssbreak
- nop // retbreak
-bd5: nop // branch displacement hi
- nop // branch displacement lo
-np5: nop // stored PC-4(next insn addr) hi
- nop // stored PC-4(next insn addr) lo
+++ /dev/null
-/**
- * @file uprobe/arch/asm-arm/trampoline_thumb.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Thumb trampolines.
- */
-
-
-#ifndef __ASM_ARM_TRAMPOLINE_THUMB_H
-#define __ASM_ARM_TRAMPOLINE_THUMB_H
-
-void gen_insn_execbuf_thumb(void);
-void pc_dep_insn_execbuf_thumb(void);
-void b_r_insn_execbuf_thumb(void);
-void b_off_insn_execbuf_thumb(void);
-void blx_off_insn_execbuf_thumb(void);
-void b_cond_insn_execbuf_thumb(void);
-void cbz_insn_execbuf_thumb(void);
-
-#endif /* __ASM_ARM_TRAMPOLINE_THUMB_H */
+++ /dev/null
-/**
- * swap_sc_patch.c
- * @author Dmitry Kovalenko <d.kovalenko@samsung.com>
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- *
- * Patching of sys_call_table
- */
-
-#include <ksyms/ksyms.h>
-#include "swap_sc_patch.h"
-
-static unsigned long original_syscall;
-static int patched_syscall = -1;
-
-/* disable write protection */
-#define swap_disable_wprot() \
- asm("pushl %eax \n" \
- "movl %cr0, %eax \n" \
- "andl $0xfffeffff, %eax \n" \
- "movl %eax, %cr0 \n" \
- "popl %eax");
-
-/* enable write protection */
-#define swap_enable_wprot() \
- asm("push %eax \n" \
- "movl %cr0, %eax \n" \
- "orl $0x00010000, %eax \n" \
- "movl %eax, %cr0 \n" \
- "popl %eax");
-
-void patch_syscall(int syscall_n, unsigned long new_syscall_addr)
-{
- unsigned long tmp;
- unsigned long *sc_table;
-
- /*
- * Search for sys_call_table (4 bytes before sysenter_after_call)
- * sysenter_do_call function which locates before sysenter_after_call
- * has sys_call_table address in call instruction (latest instruction)
- */
- tmp = swap_ksyms("sysenter_after_call");
- sc_table = *(unsigned long **)(tmp - 4);
-
- swap_disable_wprot();
- original_syscall = sc_table[syscall_n];
- sc_table[syscall_n] = new_syscall_addr;
- patched_syscall = syscall_n;
- swap_enable_wprot();
-}
-
-void swap_depatch_syscall(void)
-{
- if (patched_syscall == -1) {
- printk(KERN_WARNING
- "SWAP SC_PATCH: there is no patched syscalls");
- return;
- }
-
- patch_syscall(patched_syscall, original_syscall);
- patched_syscall = -1;
-}
-
-asmlinkage long sys_swap_func(void)
-{
- /* Your code here */
-
- return -ENOSYS;
-}
-
-#define NI_SYSCALL4SWAP 31
-void swap_patch_syscall(void)
-{
- patch_syscall(NI_SYSCALL4SWAP, (unsigned long)&sys_swap_func);
-}
+++ /dev/null
-void swap_depatch_syscall(void);
-void swap_patch_syscall(void);
+++ /dev/null
-/**
- * uprobe/arch/asm-x86/swap_uprobes.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Arch-dependent uprobe interface implementation for x86.
- */
-
-
-#include <linux/kdebug.h>
-
-#include <kprobe/swap_slots.h>
-#include <uprobe/swap_uprobes.h>
-
-#include "swap_uprobes.h"
-
-
-/**
- * @struct uprobe_ctlblk
- * @brief Uprobe control block
- */
-struct uprobe_ctlblk {
- unsigned long flags; /**< Flags */
- struct kprobe *p; /**< Pointer to the uprobe's kprobe */
-};
-
-static unsigned long trampoline_addr(struct uprobe *up)
-{
- return (unsigned long)(up->kp.ainsn.insn +
- UPROBES_TRAMP_RET_BREAK_IDX);
-}
-
-unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
-{
- return trampoline_addr(&ri->rp->up);
-}
-
-static struct uprobe_ctlblk *current_ucb(void)
-{
- /* FIXME hardcoded offset */
- return (struct uprobe_ctlblk *)(end_of_stack(current) + 20);
-}
-
-static struct kprobe *get_current_probe(void)
-{
- return current_ucb()->p;
-}
-
-static void set_current_probe(struct kprobe *p)
-{
- current_ucb()->p = p;
-}
-
-static void save_current_flags(struct pt_regs *regs)
-{
- current_ucb()->flags = regs->flags;
-}
-
-static void restore_current_flags(struct pt_regs *regs, unsigned long flags)
-{
- regs->flags &= ~IF_MASK;
- regs->flags |= flags & IF_MASK;
-}
-
-/**
- * @brief Prepares uprobe for x86.
- *
- * @param up Pointer to the uprobe.
- * @return 0 on success,\n
- * -1 on error.
- */
-int arch_prepare_uprobe(struct uprobe *up)
-{
- struct kprobe *p = up2kp(up);
- struct task_struct *task = up->task;
- u8 *tramp = up->atramp.tramp;
- enum { call_relative_opcode = 0xe8 };
-
- if (!read_proc_vm_atomic(task, (unsigned long)p->addr,
- tramp, MAX_INSN_SIZE)) {
- printk(KERN_ERR "failed to read memory %p!\n", p->addr);
- return -EINVAL;
- }
- /* TODO: this is a workaround */
- if (tramp[0] == call_relative_opcode) {
- printk(KERN_INFO "cannot install probe: 1st instruction is call\n");
- return -EINVAL;
- }
-
- tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
-
- /* TODO: remove dual info */
- p->opcode = tramp[0];
-
- p->ainsn.boostable = swap_can_boost(tramp) ? 0 : -1;
-
- p->ainsn.insn = swap_slot_alloc(up->sm);
- if (p->ainsn.insn == NULL) {
- printk(KERN_ERR "trampoline out of memory\n");
- return -ENOMEM;
- }
-
- if (!write_proc_vm_atomic(task, (unsigned long)p->ainsn.insn,
- tramp, sizeof(up->atramp.tramp))) {
- swap_slot_free(up->sm, p->ainsn.insn);
- printk(KERN_INFO "failed to write memory %p!\n", tramp);
- return -EINVAL;
- }
-
- /* for uretprobe */
- add_uprobe_table(p);
-
- return 0;
-}
-
-/**
- * @brief Jump pre-handler.
- *
- * @param p Pointer to the uprobe's kprobe.
- * @param regs Pointer to CPU register data.
- * @return 0.
- */
-int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct uprobe *up = container_of(p, struct uprobe, kp);
- struct ujprobe *jp = container_of(up, struct ujprobe, up);
- kprobe_pre_entry_handler_t pre_entry =
- (kprobe_pre_entry_handler_t)jp->pre_entry;
- entry_point_t entry = (entry_point_t)jp->entry;
- unsigned long args[6];
-
- /* FIXME some user space apps crash if we clean interrupt bit */
- /* regs->EREG(flags) &= ~IF_MASK; */
- trace_hardirqs_off();
-
- /* read first 6 args from stack */
- if (!read_proc_vm_atomic(current, regs->EREG(sp) + 4,
- args, sizeof(args)))
- printk(KERN_WARNING
- "failed to read user space func arguments %lx!\n",
- regs->sp + 4);
-
- if (pre_entry)
- p->ss_addr[smp_processor_id()] = (kprobe_opcode_t *)
- pre_entry(jp->priv_arg, regs);
-
- if (entry)
- entry(args[0], args[1], args[2], args[3], args[4], args[5]);
- else
- arch_ujprobe_return();
-
- return 0;
-}
-
-/**
- * @brief Prepares uretprobe for x86.
- *
- * @param ri Pointer to the uretprobe instance.
- * @param regs Pointer to CPU register data.
- * @return Void.
- */
-int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- /* Replace the return addr with trampoline addr */
- unsigned long ra = trampoline_addr(&ri->rp->up);
- unsigned long ret_addr;
- ri->sp = (kprobe_opcode_t *)regs->sp;
-
- if (get_user(ret_addr, (unsigned long *)regs->sp)) {
- pr_err("failed to read user space func ra %lx addr=%p!\n",
- regs->sp, ri->rp->up.kp.addr);
- return -EINVAL;
- }
-
- if (put_user(ra, (unsigned long *)regs->sp)) {
- pr_err("failed to write user space func ra %lx!\n", regs->sp);
- return -EINVAL;
- }
-
- ri->ret_addr = (kprobe_opcode_t *)ret_addr;
-
- return 0;
-}
-
-/**
- * @brief Disarms uretprobe on x86 arch.
- *
- * @param ri Pointer to the uretprobe instance.
- * @param task Pointer to the task for which the probe.
- * @return 0 on success,\n
- * negative error code on error.
- */
-int arch_disarm_urp_inst(struct uretprobe_instance *ri,
- struct task_struct *task, unsigned long tr)
-{
- unsigned long ret_addr;
- unsigned long sp = (unsigned long)ri->sp;
- unsigned long tramp_addr;
-
- if (tr == 0)
- tramp_addr = arch_tramp_by_ri(ri);
- else
- tramp_addr = tr; /* ri - invalid */
-
- if (get_user(ret_addr, (unsigned long *)sp)) {
- printk(KERN_INFO "---> %s (%d/%d): failed to read stack from %08lx\n",
- task->comm, task->tgid, task->pid, sp);
- return -EFAULT;
- }
-
- if (tramp_addr == ret_addr) {
- if (put_user((unsigned long)ri->ret_addr, (unsigned long *)sp)) {
- printk(KERN_INFO "---> %s (%d/%d): failed to write "
- "orig_ret_addr to %08lx",
- task->comm, task->tgid, task->pid, sp);
- return -EFAULT;
- }
- } else {
- printk(KERN_INFO "---> %s (%d/%d): trampoline NOT found at sp = %08lx\n",
- task->comm, task->tgid, task->pid, sp);
- return -ENOENT;
- }
-
- return 0;
-}
-
-/**
- * @brief Gets trampoline address.
- *
- * @param p Pointer to the uprobe's kprobe.
- * @param regs Pointer to CPU register data.
- * @return Trampoline address.
- */
-unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs)
-{
- return trampoline_addr(kp2up(p));
-}
-
-/**
- * @brief Restores return address.
- *
- * @param orig_ret_addr Original return address.
- * @param regs Pointer to CPU register data.
- * @return Void.
- */
-void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
-{
- regs->EREG(ip) = orig_ret_addr;
-}
-
-/**
- * @brief Removes uprobe.
- *
- * @param up Pointer to the target uprobe.
- * @return Void.
- */
-void arch_remove_uprobe(struct uprobe *up)
-{
- struct kprobe *p = up2kp(up);
-
- swap_slot_free(up->sm, p->ainsn.insn);
-}
-
-int arch_arm_uprobe(struct uprobe *p)
-{
- int ret;
- kprobe_opcode_t insn = BREAKPOINT_INSTRUCTION;
- unsigned long vaddr = (unsigned long)p->kp.addr;
-
- ret = write_proc_vm_atomic(p->task, vaddr, &insn, sizeof(insn));
- if (!ret) {
- pr_err("arch_arm_uprobe: failed to write memory tgid=%u vaddr=%08lx\n",
- p->task->tgid, vaddr);
-
- return -EACCES;
- }
-
- return 0;
-}
-
-void arch_disarm_uprobe(struct kprobe *p, struct task_struct *task)
-{
- int ret;
- unsigned long vaddr = (unsigned long)p->addr;
-
- ret = write_proc_vm_atomic(task, vaddr, &p->opcode, sizeof(p->opcode));
- if (!ret) {
- pr_err("arch_disarm_uprobe: failed to write memory tgid=%u, vaddr=%08lx\n",
- task->tgid, vaddr);
- }
-}
-
-static void set_user_jmp_op(void *from, void *to)
-{
- struct __arch_jmp_op {
- char op;
- long raddr;
- } __packed jop;
-
- jop.raddr = (long)(to) - ((long)(from) + 5);
- jop.op = RELATIVEJUMP_INSTRUCTION;
-
- if (put_user(jop.op, (char *)from) ||
- put_user(jop.raddr, (long *)(from + 1)))
- pr_err("failed to write jump opcode to user space %p\n", from);
-}
-
-static void resume_execution(struct kprobe *p,
- struct pt_regs *regs,
- unsigned long flags)
-{
- unsigned long *tos, tos_dword = 0;
- unsigned long copy_eip = (unsigned long)p->ainsn.insn;
- unsigned long orig_eip = (unsigned long)p->addr;
- kprobe_opcode_t insns[2];
-
- regs->EREG(flags) &= ~TF_MASK;
-
- tos = (unsigned long *)&tos_dword;
- if (get_user(tos_dword, (unsigned long *)regs->sp)) {
- pr_err("failed to read from user space sp=%lx!\n", regs->sp);
- return;
- }
-
- if (get_user(*(unsigned short *)insns, (unsigned short *)p->ainsn.insn)) {
- pr_err("failed to read first 2 opcodes %p!\n", p->ainsn.insn);
- return;
- }
-
- switch (insns[0]) {
- case 0x9c: /* pushfl */
- *tos &= ~(TF_MASK | IF_MASK);
- *tos |= flags & (TF_MASK | IF_MASK);
- break;
- case 0xc2: /* iret/ret/lret */
- case 0xc3:
- case 0xca:
- case 0xcb:
- case 0xcf:
- case 0xea: /* jmp absolute -- eip is correct */
- /* eip is already adjusted, no more changes required */
- p->ainsn.boostable = 1;
- goto no_change;
- case 0xe8: /* call relative - Fix return addr */
- *tos = orig_eip + (*tos - copy_eip);
- break;
- case 0x9a: /* call absolute -- same as call absolute, indirect */
- *tos = orig_eip + (*tos - copy_eip);
-
- if (put_user(tos_dword, (unsigned long *)regs->sp)) {
- pr_err("failed to write dword to sp=%lx\n", regs->sp);
- return;
- }
-
- goto no_change;
- case 0xff:
- if ((insns[1] & 0x30) == 0x10) {
- /*
- * call absolute, indirect
- * Fix return addr; eip is correct.
- * But this is not boostable
- */
- *tos = orig_eip + (*tos - copy_eip);
-
- if (put_user(tos_dword, (unsigned long *)regs->sp)) {
- pr_err("failed to write dword to sp=%lx\n", regs->sp);
- return;
- }
-
- goto no_change;
- } else if (((insns[1] & 0x31) == 0x20) || /* jmp near, absolute
- * indirect */
- ((insns[1] & 0x31) == 0x21)) {
- /* jmp far, absolute indirect */
- /* eip is correct. And this is boostable */
- p->ainsn.boostable = 1;
- goto no_change;
- }
- case 0xf3:
- if (insns[1] == 0xc3)
- /* repz ret special handling: no more changes */
- goto no_change;
- break;
- default:
- break;
- }
-
- if (put_user(tos_dword, (unsigned long *)regs->sp)) {
- pr_err("failed to write dword to sp=%lx\n", regs->sp);
- return;
- }
-
- if (p->ainsn.boostable == 0) {
- if ((regs->EREG(ip) > copy_eip) && (regs->EREG(ip) - copy_eip) +
- 5 < MAX_INSN_SIZE) {
- /*
- * These instructions can be executed directly if it
- * jumps back to correct address.
- */
- set_user_jmp_op((void *) regs->EREG(ip),
- (void *)orig_eip +
- (regs->EREG(ip) - copy_eip));
- p->ainsn.boostable = 1;
- } else {
- p->ainsn.boostable = -1;
- }
- }
-
- regs->EREG(ip) = orig_eip + (regs->EREG(ip) - copy_eip);
-
-no_change:
- return;
-}
-
-static bool prepare_ss_addr(struct kprobe *p, struct pt_regs *regs)
-{
- unsigned long *ss_addr = (long *)&p->ss_addr[smp_processor_id()];
-
- if (*ss_addr) {
- regs->ip = *ss_addr;
- *ss_addr = 0;
- return true;
- } else {
- regs->ip = (unsigned long)p->ainsn.insn;
- return false;
- }
-}
-
-static void prepare_ss(struct pt_regs *regs)
-{
- /* set single step mode */
- regs->flags |= TF_MASK;
- regs->flags &= ~IF_MASK;
-}
-
-static int uprobe_handler(struct pt_regs *regs)
-{
- struct kprobe *p;
- kprobe_opcode_t *addr;
- struct task_struct *task = current;
- pid_t tgid = task->tgid;
-
- save_current_flags(regs);
-
- addr = (kprobe_opcode_t *)(regs->EREG(ip) - sizeof(kprobe_opcode_t));
- p = get_ukprobe(addr, tgid);
-
- if (p == NULL) {
- void *tramp_addr = (void *)addr - UPROBES_TRAMP_RET_BREAK_IDX;
-
- p = get_ukprobe_by_insn_slot(tramp_addr, tgid, regs);
- if (p == NULL) {
- printk(KERN_INFO "no_uprobe\n");
- return 0;
- }
-
- trampoline_uprobe_handler(p, regs);
- return 1;
- } else {
- if (!p->pre_handler || !p->pre_handler(p, regs)) {
- if (p->ainsn.boostable == 1 && !p->post_handler) {
- prepare_ss_addr(p, regs);
- return 1;
- }
-
- if (prepare_ss_addr(p, regs) == false) {
- set_current_probe(p);
- prepare_ss(regs);
- }
- }
- }
-
- return 1;
-}
-
-static int post_uprobe_handler(struct pt_regs *regs)
-{
- struct kprobe *p = get_current_probe();
- unsigned long flags = current_ucb()->flags;
-
- if (p == NULL) {
- printk("task[%u %u %s] current uprobe is not found\n",
- current->tgid, current->pid, current->comm);
- return 0;
- }
-
- resume_execution(p, regs, flags);
- restore_current_flags(regs, flags);
-
- /* clean stack */
- current_ucb()->p = 0;
- current_ucb()->flags = 0;
-
- return 1;
-}
-
-static int uprobe_exceptions_notify(struct notifier_block *self,
- unsigned long val, void *data)
-{
- struct die_args *args = (struct die_args *)data;
- int ret = NOTIFY_DONE;
-
- if (args->regs == NULL || !user_mode_vm(args->regs))
- return ret;
-
- switch (val) {
-#ifdef CONFIG_KPROBES
- case DIE_INT3:
-#else
- case DIE_TRAP:
-#endif
- if (uprobe_handler(args->regs))
- ret = NOTIFY_STOP;
- break;
- case DIE_DEBUG:
- if (post_uprobe_handler(args->regs))
- ret = NOTIFY_STOP;
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static struct notifier_block uprobe_exceptions_nb = {
- .notifier_call = uprobe_exceptions_notify,
- .priority = INT_MAX
-};
-
-/**
- * @brief Registers notify.
- *
- * @return register_die_notifier result.
- */
-int swap_arch_init_uprobes(void)
-{
- return register_die_notifier(&uprobe_exceptions_nb);
-}
-
-/**
- * @brief Unregisters notify.
- *
- * @return Void.
- */
-void swap_arch_exit_uprobes(void)
-{
- unregister_die_notifier(&uprobe_exceptions_nb);
-}
-
+++ /dev/null
-/**
- * @file uprobe/arch/asm-x86/swap_uprobes.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Arch-dependent uprobe interface declaration.
- */
-
-#ifndef _X86_SWAP_UPROBES_H
-#define _X86_SWAP_UPROBES_H
-
-
-#include <swap-asm/swap_kprobes.h> /* FIXME: for UPROBES_TRAMP_LEN */
-
-
-struct uprobe;
-struct uretprobe;
-struct uretprobe_instance;
-
-/**
- * @struct arch_specific_tramp
- * @brief Stores x86 trampoline
- */
-struct arch_specific_tramp {
- u8 tramp[UPROBES_TRAMP_LEN + BP_INSN_SIZE]; /**< BP for uretprobe */
-};
-
-
-static inline u32 swap_get_urp_float(struct pt_regs *regs)
-{
- u32 st0;
-
- asm volatile ("fstps %0" : "=m" (st0));
-
- return st0;
-}
-
-static inline u64 swap_get_urp_double(struct pt_regs *regs)
-{
- u64 st1;
-
- asm volatile ("fstpl %0" : "=m" (st1));
-
- return st1;
-}
-
-static inline void arch_ujprobe_return(void)
-{
-}
-
-int arch_prepare_uprobe(struct uprobe *up);
-int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs);
-static inline int longjmp_break_uhandler(struct kprobe *p, struct pt_regs *regs)
-{
- return 0;
-}
-
-static inline int arch_opcode_analysis_uretprobe(struct uretprobe *rp)
-{
- return 0;
-}
-
-int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
-int arch_disarm_urp_inst(struct uretprobe_instance *ri,
- struct task_struct *task, unsigned long tr);
-unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri);
-unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
-void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
-void arch_remove_uprobe(struct uprobe *up);
-int arch_arm_uprobe(struct uprobe *p);
-void arch_disarm_uprobe(struct kprobe *p, struct task_struct *task);
-
-static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
-{
- u32 *ptr, addr = 0;
-
- /* 1 - return address saved on top of the stack */
- ptr = (u32 *)regs->sp + n + 1;
- if (get_user(addr, ptr))
- printk(KERN_INFO "failed to dereference a pointer, ptr=%p\n",
- ptr);
-
- return addr;
-}
-
-static inline void swap_put_uarg(struct pt_regs *regs, unsigned long n,
- unsigned long val)
-{
- u32 *ptr;
-
- /* 1 - return address saved on top of the stack */
- ptr = (u32 *)regs->sp + n + 1;
- if (put_user(val, ptr))
- printk(KERN_INFO "failed to dereference a pointer, ptr=%p\n",
- ptr);
-}
-
-int swap_arch_init_uprobes(void);
-void swap_arch_exit_uprobes(void);
-
-#endif /* _X86_SWAP_UPROBES_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/uaccess.h>
-
-
-static const char *strdup_from_user(const char __user *user_s, gfp_t gfp)
-{
- enum { max_str_len = 1024 };
- char *str;
- int len_s, ret;
-
- len_s = strnlen_user(user_s, max_str_len - 1);
- str = kmalloc(len_s + 1, gfp);
- if (str == NULL)
- return NULL;
-
- ret = copy_from_user(str, user_s, len_s);
- if (ret < 0) {
- kfree(str);
- return NULL;
- }
-
- str[len_s] = '\0';
-
- return str;
-}
+++ /dev/null
-/**
- * uprobe/swap_uprobes.c
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Uprobes implementation.
- */
-
-
-#include <linux/hash.h>
-#include <linux/mempolicy.h>
-#include <linux/module.h>
-
-#include <master/swap_initializer.h>
-#include <kprobe/swap_slots.h>
-#include <kprobe/swap_kdebug.h>
-#include <kprobe/swap_kprobes_deps.h>
-
-#include <swap-asm/swap_uprobes.h>
-
-#include "swap_uprobes.h"
-
-
-enum {
- UPROBE_HASH_BITS = 10,
- UPROBE_TABLE_SIZE = (1 << UPROBE_HASH_BITS)
-};
-
-static DEFINE_RWLOCK(st_lock);
-static struct hlist_head slot_table[UPROBE_TABLE_SIZE];
-struct hlist_head uprobe_table[UPROBE_TABLE_SIZE];
-
-DEFINE_SPINLOCK(uretprobe_lock); /* Protects uretprobe_inst_table */
-static struct hlist_head uretprobe_inst_table[UPROBE_TABLE_SIZE];
-
-#define DEBUG_PRINT_HASH_TABLE 0
-
-#if DEBUG_PRINT_HASH_TABLE
-void print_uprobe_hash_table(void)
-{
- int i;
- struct hlist_head *head;
- struct kprobe *p;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- /* print uprobe table */
- for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
- head = &uprobe_insn_slot_table[i];
- swap_hlist_for_each_entry_rcu(p, node, head, is_hlist_arm) {
- printk(KERN_INFO "####### find U tgid=%u, addr=%x\n",
- p->tgid, p->addr);
- }
- }
-}
-#endif
-
-
-struct uinst_info *uinst_info_create(unsigned long vaddr,
- kprobe_opcode_t opcode)
-{
- struct uinst_info *uinst;
-
- uinst = kmalloc(sizeof(*uinst), GFP_ATOMIC);
- if (uinst) {
- INIT_HLIST_NODE(&uinst->hlist);
- uinst->vaddr = vaddr;
- uinst->opcode = opcode;
- } else {
- pr_err("Cannot allocate memory for uinst\n");
- }
-
- return uinst;
-}
-EXPORT_SYMBOL_GPL(uinst_info_create);
-
-void uinst_info_destroy(struct uinst_info *uinst)
-{
- kfree(uinst);
-}
-EXPORT_SYMBOL_GPL(uinst_info_destroy);
-
-void uinst_info_disarm(struct uinst_info *uinst, struct task_struct *task)
-{
- int ret = write_proc_vm_atomic(task, uinst->vaddr,
- &uinst->opcode, sizeof(uinst->opcode));
- if (!ret) {
- printk("uinst_info_disarm: failed to write memory "
- "tgid=%u, vaddr=%08lx!\n", task->tgid, uinst->vaddr);
- }
-}
-EXPORT_SYMBOL_GPL(uinst_info_disarm);
-
-/*
- * Keep all fields in the uprobe consistent
- */
-static inline void copy_uprobe(struct kprobe *old_p, struct kprobe *p)
-{
- memcpy(&p->opcode, &old_p->opcode, sizeof(kprobe_opcode_t));
- memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_specific_insn));
-}
-
-/*
- * Aggregate handlers for multiple uprobes support - these handlers
- * take care of invoking the individual uprobe handlers on p->list
- */
-static int aggr_pre_uhandler(struct kprobe *p, struct pt_regs *regs)
-{
- struct kprobe *kp;
- int ret;
-
- list_for_each_entry_rcu(kp, &p->list, list) {
- if (kp->pre_handler) {
- ret = kp->pre_handler(kp, regs);
- if (ret)
- return ret;
- }
- }
-
- return 0;
-}
-
-static void aggr_post_uhandler(struct kprobe *p, struct pt_regs *regs,
- unsigned long flags)
-{
- struct kprobe *kp;
-
- list_for_each_entry_rcu(kp, &p->list, list) {
- if (kp->post_handler)
- kp->post_handler(kp, regs, flags);
- }
-}
-
-static int aggr_fault_uhandler(struct kprobe *p,
- struct pt_regs *regs,
- int trapnr)
-{
- return 0;
-}
-
-static int aggr_break_uhandler(struct kprobe *p, struct pt_regs *regs)
-{
- return 0;
-}
-
-/*
- * Add the new probe to old_p->list. Fail if this is the
- * second ujprobe at the address - two ujprobes can't coexist
- */
-static int add_new_uprobe(struct kprobe *old_p, struct kprobe *p)
-{
- if (p->break_handler) {
- if (old_p->break_handler)
- return -EEXIST;
-
- list_add_tail_rcu(&p->list, &old_p->list);
- old_p->break_handler = aggr_break_uhandler;
- } else {
- list_add_rcu(&p->list, &old_p->list);
- }
-
- if (p->post_handler && !old_p->post_handler)
- old_p->post_handler = aggr_post_uhandler;
-
- return 0;
-}
-
-/*
- * Fill in the required fields of the "manager uprobe". Replace the
- * earlier uprobe in the hlist with the manager uprobe
- */
-static inline void add_aggr_uprobe(struct kprobe *ap, struct kprobe *p)
-{
- copy_uprobe(p, ap);
-
- ap->addr = p->addr;
- ap->pre_handler = aggr_pre_uhandler;
- ap->fault_handler = aggr_fault_uhandler;
-
- if (p->post_handler)
- ap->post_handler = aggr_post_uhandler;
-
- if (p->break_handler)
- ap->break_handler = aggr_break_uhandler;
-
- INIT_LIST_HEAD(&ap->list);
- list_add_rcu(&p->list, &ap->list);
-
- hlist_replace_rcu(&p->hlist, &ap->hlist);
-}
-
-/*
- * This is the second or subsequent uprobe at the address - handle
- * the intricacies
- */
-static int register_aggr_uprobe(struct kprobe *old_p, struct kprobe *p)
-{
- int ret = 0;
- struct kprobe *ap;
-
- if (old_p->pre_handler == aggr_pre_uhandler) {
- copy_uprobe(old_p, p);
- ret = add_new_uprobe(old_p, p);
- } else {
- struct uprobe *uap = kzalloc(sizeof(*uap), GFP_KERNEL);
- if (!uap)
- return -ENOMEM;
-
- uap->task = kp2up(p)->task;
- ap = up2kp(uap);
- add_aggr_uprobe(ap, old_p);
- copy_uprobe(ap, p);
- ret = add_new_uprobe(ap, p);
- }
-
- return ret;
-}
-
-static int arm_uprobe(struct uprobe *p)
-{
- return arch_arm_uprobe(p);
-}
-
-/**
- * @brief Disarms uprobe.
- *
- * @param p Pointer to the uprobe's kprobe.
- * @param task Pointer to the target task.
- * @return Void.
- */
-void disarm_uprobe(struct kprobe *p, struct task_struct *task)
-{
- arch_disarm_uprobe(p, task);
-}
-EXPORT_SYMBOL_GPL(disarm_uprobe);
-
-static void init_uprobes_insn_slots(void)
-{
- int i;
- for (i = 0; i < UPROBE_TABLE_SIZE; ++i)
- INIT_HLIST_HEAD(&slot_table[i]);
-}
-
-static void init_uprobe_table(void)
-{
- int i;
- for (i = 0; i < UPROBE_TABLE_SIZE; ++i)
- INIT_HLIST_HEAD(&uprobe_table[i]);
-}
-
-static void init_uretprobe_inst_table(void)
-{
- int i;
- for (i = 0; i < UPROBE_TABLE_SIZE; ++i)
- INIT_HLIST_HEAD(&uretprobe_inst_table[i]);
-}
-
-/**
- * @brief Gets uprobe's kprobe.
- *
- * @param addr Probe's address.
- * @param tgid Probes's thread group ID.
- * @return Pointer to the kprobe on success,\n
- * NULL otherwise.
- */
-struct kprobe *get_ukprobe(void *addr, pid_t tgid)
-{
- struct hlist_head *head;
- struct kprobe *p;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- head = &uprobe_table[hash_ptr(addr, UPROBE_HASH_BITS)];
- swap_hlist_for_each_entry_rcu(p, node, head, hlist) {
- if (p->addr == addr && kp2up(p)->task->tgid == tgid)
- return p;
- }
-
- return NULL;
-}
-
-/**
- * @brief Adds uprobe to hlist when trampoline have been made.
- *
- * @param p Pointer to the uprobe's kprobe.
- * @return Void.
- */
-void add_uprobe_table(struct kprobe *p)
-{
- write_lock(&st_lock);
- hlist_add_head(&p->is_hlist,
- &slot_table[hash_ptr(p->ainsn.insn, UPROBE_HASH_BITS)]);
- write_unlock(&st_lock);
-}
-
-static void del_uprobe_table(struct kprobe *p)
-{
- write_lock(&st_lock);
- if (!hlist_unhashed(&p->is_hlist))
- hlist_del(&p->is_hlist);
- write_unlock(&st_lock);
-}
-
-/**
- * @brief Gets kprobe by insn slot.
- *
- * @param addr Probe's address.
- * @param tgit Probe's thread group ID.
- * @param regs Pointer to CPU registers data.
- * @return Pointer to the kprobe on success,\n
- * NULL otherwise.
- */
-struct kprobe *get_ukprobe_by_insn_slot(void *addr,
- pid_t tgid,
- struct pt_regs *regs)
-{
- struct hlist_head *head;
- struct kprobe *p;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- read_lock(&st_lock);
- head = &slot_table[hash_ptr(addr, UPROBE_HASH_BITS)];
- swap_hlist_for_each_entry(p, node, head, is_hlist) {
- if (p->ainsn.insn == addr && kp2up(p)->task->tgid == tgid) {
- read_unlock(&st_lock);
- return p;
- }
- }
- read_unlock(&st_lock);
-
- return NULL;
-}
-
-
-static void remove_uprobe(struct uprobe *up)
-{
- del_uprobe_table(&up->kp);
- arch_remove_uprobe(up);
-}
-
-static struct hlist_head *uretprobe_inst_table_head(void *hash_key)
-{
- return &uretprobe_inst_table[hash_ptr(hash_key, UPROBE_HASH_BITS)];
-}
-
-/* Called with uretprobe_lock held */
-static void add_urp_inst(struct uretprobe_instance *ri)
-{
- /*
- * Remove rp inst off the free list -
- * Add it back when probed function returns
- */
- hlist_del(&ri->uflist);
-
- /* Add rp inst onto table */
- INIT_HLIST_NODE(&ri->hlist);
- hlist_add_head(&ri->hlist, uretprobe_inst_table_head(ri->task->mm));
-
- /* Also add this rp inst to the used list. */
- INIT_HLIST_NODE(&ri->uflist);
- hlist_add_head(&ri->uflist, &ri->rp->used_instances);
-}
-
-/* Called with uretprobe_lock held */
-static void recycle_urp_inst(struct uretprobe_instance *ri)
-{
- if (ri->rp) {
- hlist_del(&ri->hlist);
- /* remove rp inst off the used list */
- hlist_del(&ri->uflist);
- /* put rp inst back onto the free list */
- INIT_HLIST_NODE(&ri->uflist);
- hlist_add_head(&ri->uflist, &ri->rp->free_instances);
- }
-}
-
-/* Called with uretprobe_lock held */
-static struct uretprobe_instance *get_used_urp_inst(struct uretprobe *rp)
-{
- struct uretprobe_instance *ri;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
- return ri;
- }
-
- return NULL;
-}
-
-/**
- * @brief Gets free uretprobe instanse for the specified uretprobe without
- * allocation. Called with uretprobe_lock held.
- *
- * @param rp Pointer to the uretprobe.
- * @return Pointer to the uretprobe_instance on success,\n
- * NULL otherwise.
- */
-struct uretprobe_instance *get_free_urp_inst_no_alloc(struct uretprobe *rp)
-{
- struct uretprobe_instance *ri;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
- return ri;
- }
-
- return NULL;
-}
-
-/* Called with uretprobe_lock held */
-static void free_urp_inst(struct uretprobe *rp)
-{
- struct uretprobe_instance *ri;
- while ((ri = get_free_urp_inst_no_alloc(rp)) != NULL) {
- hlist_del(&ri->uflist);
- kfree(ri);
- }
-}
-
-#define COMMON_URP_NR 10
-
-static int alloc_nodes_uretprobe(struct uretprobe *rp)
-{
- int alloc_nodes;
- struct uretprobe_instance *inst;
- int i;
-
-#if 1 /* def CONFIG_PREEMPT */
- rp->maxactive += max(COMMON_URP_NR, 2 * NR_CPUS);
-#else
- rp->maxacpptive += NR_CPUS;
-#endif
- alloc_nodes = COMMON_URP_NR;
-
- for (i = 0; i < alloc_nodes; ++i) {
- inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_ATOMIC);
- if (inst == NULL) {
- free_urp_inst(rp);
- return -ENOMEM;
- }
- INIT_HLIST_NODE(&inst->uflist);
- hlist_add_head(&inst->uflist, &rp->free_instances);
- }
-
- return 0;
-}
-
-/* Called with uretprobe_lock held */
-static struct uretprobe_instance *get_free_urp_inst(struct uretprobe *rp)
-{
- struct uretprobe_instance *ri;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
- return ri;
- }
-
- if (!alloc_nodes_uretprobe(rp)) {
- swap_hlist_for_each_entry(ri, node,
- &rp->free_instances, uflist) {
- return ri;
- }
- }
-
- return NULL;
-}
-/* =================================================================== */
-
-/**
- * @brief Registers uprobe.
- *
- * @param up Pointer to the uprobe to register.
- * @return 0 on success,\n
- * negative error code on error.
- */
-int swap_register_uprobe(struct uprobe *up)
-{
- int ret = 0;
- struct kprobe *p, *old_p;
-
- p = &up->kp;
- if (!p->addr)
- return -EINVAL;
-
- p->ainsn.insn = NULL;
- p->mod_refcounted = 0;
- p->nmissed = 0;
- INIT_LIST_HEAD(&p->list);
-#ifdef KPROBES_PROFILE
- p->start_tm.tv_sec = p->start_tm.tv_usec = 0;
- p->hnd_tm_sum.tv_sec = p->hnd_tm_sum.tv_usec = 0;
- p->count = 0;
-#endif
-
- /* get the first item */
- old_p = get_ukprobe(p->addr, kp2up(p)->task->tgid);
- if (old_p) {
- struct task_struct *task = up->task;
-
- /* TODO: add support many uprobes on address */
- printk(KERN_INFO "uprobe on task[%u %u %s] vaddr=%p is there\n",
- task->tgid, task->pid, task->comm, p->addr);
- ret = -EINVAL;
- goto out;
-
- ret = register_aggr_uprobe(old_p, p);
- DBPRINTF("goto out\n", ret);
- goto out;
- }
-
- INIT_HLIST_NODE(&p->is_hlist);
-
- ret = arch_prepare_uprobe(up);
- if (ret) {
- DBPRINTF("goto out\n", ret);
- goto out;
- }
-
- DBPRINTF("before out ret = 0x%x\n", ret);
-
- /* TODO: add uprobe (must be in function) */
- INIT_HLIST_NODE(&p->hlist);
- hlist_add_head_rcu(&p->hlist,
- &uprobe_table[hash_ptr(p->addr, UPROBE_HASH_BITS)]);
-
- ret = arm_uprobe(up);
- if (ret) {
- hlist_del_rcu(&p->hlist);
- synchronize_rcu();
- remove_uprobe(up);
- }
-
-out:
- DBPRINTF("out ret = 0x%x\n", ret);
- return ret;
-}
-EXPORT_SYMBOL_GPL(swap_register_uprobe);
-
-/**
- * @brief Unregisters uprobe.
- *
- * @param up Pointer to the uprobe.
- * @param disarm Disarm flag. When true uprobe is disarmed.
- * @return Void.
- */
-void __swap_unregister_uprobe(struct uprobe *up, int disarm)
-{
- struct kprobe *p, *old_p, *list_p;
- int cleanup_p;
-
- p = &up->kp;
- old_p = get_ukprobe(p->addr, kp2up(p)->task->tgid);
- if (unlikely(!old_p))
- return;
-
- if (p != old_p) {
- list_for_each_entry_rcu(list_p, &old_p->list, list) {
- if (list_p == p) {
- /* uprobe p is a valid probe */
- goto valid_p;
- }
- }
-
- return;
- }
-
-valid_p:
- if ((old_p == p) || ((old_p->pre_handler == aggr_pre_uhandler) &&
- (p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) {
- /* Only probe on the hash list */
- if (disarm)
- disarm_uprobe(&up->kp, up->task);
-
- hlist_del_rcu(&old_p->hlist);
- cleanup_p = 1;
- } else {
- list_del_rcu(&p->list);
- cleanup_p = 0;
- }
-
- if (cleanup_p) {
- if (p != old_p) {
- list_del_rcu(&p->list);
- kfree(old_p);
- }
-
- if (!in_atomic())
- synchronize_sched();
-
- remove_uprobe(up);
- } else {
- if (p->break_handler)
- old_p->break_handler = NULL;
-
- if (p->post_handler) {
- list_for_each_entry_rcu(list_p, &old_p->list, list) {
- if (list_p->post_handler) {
- cleanup_p = 2;
- break;
- }
- }
-
- if (cleanup_p == 0)
- old_p->post_handler = NULL;
- }
- }
-}
-EXPORT_SYMBOL_GPL(__swap_unregister_uprobe);
-
-/**
- * @brief Unregisters uprobe. Main interface function, wrapper for
- * __swap_unregister_uprobe.
- *
- * @param up Pointer to the uprobe.
- * @return Void.
- */
-void swap_unregister_uprobe(struct uprobe *up)
-{
- __swap_unregister_uprobe(up, 1);
-}
-
-/**
- * @brief Registers ujprobe.
- *
- * @param uj Pointer to the ujprobe function.
- * @return 0 on success,\n
- * error code on error.
- */
-int swap_register_ujprobe(struct ujprobe *jp)
-{
- int ret = 0;
-
- /* Todo: Verify probepoint is a function entry point */
- jp->up.kp.pre_handler = setjmp_upre_handler;
- jp->up.kp.break_handler = longjmp_break_uhandler;
-
- ret = swap_register_uprobe(&jp->up);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(swap_register_ujprobe);
-
-/**
- * @brief Unregisters ujprobe.
- *
- * @param jp Pointer to the ujprobe.
- * @param disarm Disarm flag, passed to __swap_unregister_uprobe.
- * @return Void.
- */
-void __swap_unregister_ujprobe(struct ujprobe *jp, int disarm)
-{
- __swap_unregister_uprobe(&jp->up, disarm);
-}
-EXPORT_SYMBOL_GPL(__swap_unregister_ujprobe);
-
-/**
- * @brief Unregisters ujprobe. Main interface function, wrapper for
- * __swap_unregister_ujprobe.
- *
- * @param jp Pointer to the jprobe.
- * @return Void.
- */
-void swap_unregister_ujprobe(struct ujprobe *jp)
-{
- __swap_unregister_ujprobe(jp, 1);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_ujprobe);
-
-/**
- * @brief Trampoline uprobe handler.
- *
- * @param p Pointer to the uprobe's kprobe.
- * @param regs Pointer to CPU register data.
- * @return 1
- */
-int trampoline_uprobe_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct uretprobe_instance *ri = NULL;
- struct kprobe *kp;
- struct hlist_head *head;
- unsigned long flags, tramp_addr, orig_ret_addr = 0;
- struct hlist_node *tmp;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- tramp_addr = arch_get_trampoline_addr(p, regs);
- spin_lock_irqsave(&uretprobe_lock, flags);
-
- head = uretprobe_inst_table_head(current->mm);
-
- /*
- * It is possible to have multiple instances associated with a given
- * task either because an multiple functions in the call path
- * have a return probe installed on them, and/or more then one
- * return probe was registered for a target function.
- *
- * We can handle this because:
- * - instances are always inserted at the head of the list
- * - when multiple return probes are registered for the same
- * function, the first instance's ret_addr will point to the
- * real return address, and all the rest will point to
- * uretprobe_trampoline
- */
- swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
- if (ri->task != current) {
- /* another task is sharing our hash bucket */
- continue;
- }
-
- kp = NULL;
- if (ri->rp) {
- kp = up2kp(&ri->rp->up);
-
- if (ri->rp->handler)
- ri->rp->handler(ri, regs);
- }
-
- orig_ret_addr = (unsigned long)ri->ret_addr;
- recycle_urp_inst(ri);
-
- if ((orig_ret_addr != tramp_addr && kp == p) || kp == NULL) {
- /*
- * This is the real return address. Any other
- * instances associated with this task are for
- * other calls deeper on the call stack
- */
- break;
- }
- }
-
- spin_unlock_irqrestore(&uretprobe_lock, flags);
- /* orig_ret_addr is NULL when there is no need to restore anything
- * (all the magic is performed inside handler) */
- if (likely(orig_ret_addr))
- arch_set_orig_ret_addr(orig_ret_addr, regs);
-
- return 1;
-}
-
-static int pre_handler_uretprobe(struct kprobe *p, struct pt_regs *regs)
-{
- struct uprobe *up = container_of(p, struct uprobe, kp);
- struct uretprobe *rp = container_of(up, struct uretprobe, up);
-#ifdef CONFIG_ARM
- int noret = thumb_mode(regs) ? rp->thumb_noret : rp->arm_noret;
-#endif
- struct uretprobe_instance *ri;
- unsigned long flags;
-
-#ifdef CONFIG_ARM
- if (noret)
- return 0;
-#endif
-
- /* TODO: consider to only swap the
- * RA after the last pre_handler fired */
- spin_lock_irqsave(&uretprobe_lock, flags);
-
- /* TODO: test - remove retprobe after func entry but before its exit */
- ri = get_free_urp_inst(rp);
- if (ri != NULL) {
- int ret;
-
- ri->rp = rp;
- ri->task = current;
-#ifdef CONFIG_ARM
- ri->preload_thumb = 0;
-#endif
-
- if (rp->entry_handler)
- rp->entry_handler(ri, regs);
-
- ret = arch_prepare_uretprobe(ri, regs);
- add_urp_inst(ri);
- if (ret) {
- recycle_urp_inst(ri);
- ++rp->nmissed;
- }
- } else {
- ++rp->nmissed;
- }
-
- spin_unlock_irqrestore(&uretprobe_lock, flags);
-
- return 0;
-}
-
-/**
- * @brief Registers uretprobe.
- *
- * @param rp Pointer to the uretprobe.
- * @return 0 on success,\n
- * negative error code on error.
- */
-int swap_register_uretprobe(struct uretprobe *rp)
-{
- int i, ret = 0;
- struct uretprobe_instance *inst;
-
- DBPRINTF("START\n");
-
- rp->up.kp.pre_handler = pre_handler_uretprobe;
- rp->up.kp.post_handler = NULL;
- rp->up.kp.fault_handler = NULL;
- rp->up.kp.break_handler = NULL;
-
- /* Pre-allocate memory for max kretprobe instances */
- if (rp->maxactive <= 0) {
-#if 1 /* def CONFIG_PREEMPT */
- rp->maxactive = max(10, 2 * NR_CPUS);
-#else
- rp->maxactive = NR_CPUS;
-#endif
- }
-
- INIT_HLIST_HEAD(&rp->used_instances);
- INIT_HLIST_HEAD(&rp->free_instances);
-
- for (i = 0; i < rp->maxactive; i++) {
- inst = kmalloc(sizeof(*inst) + rp->data_size, GFP_KERNEL);
- if (inst == NULL) {
- free_urp_inst(rp);
- return -ENOMEM;
- }
-
- INIT_HLIST_NODE(&inst->uflist);
- hlist_add_head(&inst->uflist, &rp->free_instances);
- }
-
- rp->nmissed = 0;
-
- /* Establish function entry probe point */
- ret = swap_register_uprobe(&rp->up);
- if (ret)
- return ret;
-
- arch_opcode_analysis_uretprobe(rp);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(swap_register_uretprobe);
-
-/**
- * @brief Unregisters uretprobe.
- *
- * @param rp Pointer to the ureprobe.
- * @param disarm Disarm flag, passed to __swap_unregister_uprobe
- * @return Void.
- */
-void __swap_unregister_uretprobe(struct uretprobe *rp, int disarm)
-{
- unsigned long flags;
- struct uretprobe_instance *ri;
-
- __swap_unregister_uprobe(&rp->up, disarm);
-
- spin_lock_irqsave(&uretprobe_lock, flags);
- while ((ri = get_used_urp_inst(rp)) != NULL) {
- bool is_current = ri->task == current;
-
- if (is_current)
- spin_unlock_irqrestore(&uretprobe_lock, flags);
-
- /* FIXME: arch_disarm_urp_inst() for no current context */
- if (arch_disarm_urp_inst(ri, ri->task, 0) != 0)
- printk(KERN_INFO "%s (%d/%d): "
- "cannot disarm urp instance (%08lx)\n",
- ri->task->comm, ri->task->tgid, ri->task->pid,
- (unsigned long)rp->up.kp.addr);
-
- if (is_current)
- spin_lock_irqsave(&uretprobe_lock, flags);
-
- recycle_urp_inst(ri);
- }
- while ((ri = get_used_urp_inst(rp)) != NULL) {
- ri->rp = NULL;
- hlist_del(&ri->uflist);
- }
- spin_unlock_irqrestore(&uretprobe_lock, flags);
-
- free_urp_inst(rp);
-}
-EXPORT_SYMBOL_GPL(__swap_unregister_uretprobe);
-
-/**
- * @brief Unregistets uretprobe. Main interface function, wrapper for
- * __swap_unregister_uretprobe.
- *
- * @param rp Pointer to the uretprobe.
- * @return Void.
- */
-void swap_unregister_uretprobe(struct uretprobe *rp)
-{
- __swap_unregister_uretprobe(rp, 1);
-}
-EXPORT_SYMBOL_GPL(swap_unregister_uretprobe);
-
-/**
- * @brief Unregisters all uprobes for task's thread group ID.
- *
- * @param task Pointer to the task_struct
- * @return Void.
- */
-void swap_unregister_all_uprobes(struct task_struct *task)
-{
- struct hlist_head *head;
- struct kprobe *p;
- int i;
- struct hlist_node *tnode;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
- head = &uprobe_table[i];
- swap_hlist_for_each_entry_safe(p, node, tnode, head, hlist) {
- if (kp2up(p)->task->tgid == task->tgid) {
- struct uprobe *up =
- container_of(p, struct uprobe, kp);
- printk(KERN_INFO "%s: delete uprobe at %p[%lx]"
- " for %s/%d\n", __func__, p->addr,
- (unsigned long)p->opcode,
- task->comm, task->pid);
- swap_unregister_uprobe(up);
- }
- }
- }
-}
-EXPORT_SYMBOL_GPL(swap_unregister_all_uprobes);
-
-/**
- * @brief Arch-independent wrapper for arch_ujprobe_return.
- *
- * @return Void.
- */
-void swap_ujprobe_return(void)
-{
- arch_ujprobe_return();
-}
-EXPORT_SYMBOL_GPL(swap_ujprobe_return);
-
-
-static struct urinst_info *urinst_info_create(struct uretprobe_instance *ri)
-{
- struct urinst_info *urinst;
-
- urinst = kmalloc(sizeof(*urinst), GFP_ATOMIC);
- if (urinst) {
- INIT_HLIST_NODE(&urinst->hlist);
- urinst->task = ri->task;
- urinst->sp = (unsigned long)ri->sp;
- urinst->tramp = arch_tramp_by_ri(ri);
- urinst->ret_addr = (unsigned long)ri->ret_addr;
- } else {
- pr_err("Cannot allocate memory for urinst\n");
- }
-
- return urinst;
-}
-
-static void urinst_info_destroy(struct urinst_info *urinst)
-{
- kfree(urinst);
-}
-
-static void urinst_info_disarm(struct urinst_info *urinst, struct task_struct *task)
-{
- struct uretprobe_instance ri;
- unsigned long tramp = urinst->tramp;
-
- /* set necessary data*/
- ri.task = urinst->task;
- ri.sp = (kprobe_opcode_t *)urinst->sp;
- ri.ret_addr = (kprobe_opcode_t *)urinst->ret_addr;
-
- arch_disarm_urp_inst(&ri, task, tramp);
-}
-
-void urinst_info_get_current_hlist(struct hlist_head *head, bool recycle)
-{
- unsigned long flags;
- struct task_struct *task = current;
- struct uretprobe_instance *ri;
- struct hlist_head *hhead;
- struct hlist_node *n;
- struct hlist_node *last = NULL;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- spin_lock_irqsave(&uretprobe_lock, flags);
- hhead = uretprobe_inst_table_head(task->mm);
- swap_hlist_for_each_entry_safe(ri, node, n, hhead, hlist) {
- if (task == ri->task) {
- struct urinst_info *urinst;
-
- urinst = urinst_info_create(ri);
- if (urinst) {
- if (last)
- hlist_add_after(last, &urinst->hlist);
- else
- hlist_add_head(&urinst->hlist, head);
-
- last = &urinst->hlist;
- }
-
- if (recycle)
- recycle_urp_inst(ri);
- }
- }
- spin_unlock_irqrestore(&uretprobe_lock, flags);
-}
-EXPORT_SYMBOL_GPL(urinst_info_get_current_hlist);
-
-void urinst_info_put_current_hlist(struct hlist_head *head,
- struct task_struct *task)
-{
- struct urinst_info *urinst;
- struct hlist_node *tmp;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- swap_hlist_for_each_entry_safe(urinst, node, tmp, head, hlist) {
- /* check on disarm */
- if (task)
- urinst_info_disarm(urinst, task);
-
- hlist_del(&urinst->hlist);
- urinst_info_destroy(urinst);
- }
-}
-EXPORT_SYMBOL_GPL(urinst_info_put_current_hlist);
-
-
-static int once(void)
-{
- init_uprobe_table();
- init_uprobes_insn_slots();
- init_uretprobe_inst_table();
-
- return 0;
-}
-
-SWAP_LIGHT_INIT_MODULE(once, swap_arch_init_uprobes, swap_arch_exit_uprobes,
- NULL, NULL);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/**
- * @file uprobe/swap_uprobes.h
- * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial
- * implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for
- * separating core and arch parts
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2006-2010
- *
- * @section DESCRIPTION
- *
- * Uprobes interface declaration.
- */
-
-#ifndef _SWAP_UPROBES_H
-#define _SWAP_UPROBES_H
-
-
-#include <kprobe/swap_kprobes.h>
-
-#include <swap-asm/swap_uprobes.h>
-
-
-/**
- * @struct uprobe
- * @brief Stores uprobe data, based on kprobe.
- */
-struct uprobe {
- struct kprobe kp; /**< Kprobe for this uprobe */
- struct task_struct *task; /**< Pointer to the task struct */
- struct slot_manager *sm; /**< Pointer to slot manager */
- struct arch_specific_tramp atramp; /**< Stores trampoline */
- bool atomic_ctx; /**< Handler context */
-};
-
-struct uinst_info {
- struct hlist_node hlist;
-
- unsigned long vaddr;
- kprobe_opcode_t opcode;
-};
-
-struct urinst_info {
- struct hlist_node hlist;
-
- struct task_struct *task;
- unsigned long sp;
- unsigned long tramp;
- unsigned long ret_addr;
-};
-
-struct uinst_info *uinst_info_create(unsigned long vaddr,
- kprobe_opcode_t opcode);
-void uinst_info_destroy(struct uinst_info *uinst);
-void uinst_info_disarm(struct uinst_info *uinst, struct task_struct *task);
-
-
-void urinst_info_get_current_hlist(struct hlist_head *head, bool recycle);
-void urinst_info_put_current_hlist(struct hlist_head *head,
- struct task_struct *task);
-
-
-/**
- * @brief Uprobe pre-entry handler.
- */
-typedef unsigned long (*uprobe_pre_entry_handler_t)(void *priv_arg,
- struct pt_regs *regs);
-
-/**
- * @struct ujprobe
- * @brief Stores ujprobe data, based on uprobe.
- */
-struct ujprobe {
- struct uprobe up; /**< Uprobe for this ujprobe */
- void *entry; /**< Probe handling code to jump to */
- /** Handler which will be called before 'entry' */
- uprobe_pre_entry_handler_t pre_entry;
- void *priv_arg; /**< Private args for handler */
- char *args; /**< Function args format string */
-};
-
-struct uretprobe_instance;
-
-/**
- * @brief Uretprobe handler.
- */
-typedef int (*uretprobe_handler_t)(struct uretprobe_instance *,
- struct pt_regs *);
-
-/**
- * @strict uretprobe
- * @brief Function-return probe.
- *
- * Note:
- * User needs to provide a handler function, and initialize maxactive.
- */
-struct uretprobe {
- struct uprobe up; /**< Uprobe for this uretprobe */
- uretprobe_handler_t handler; /**< Uretprobe handler */
- uretprobe_handler_t entry_handler; /**< Uretprobe entry handler */
- /** Maximum number of instances of the probed function that can be
- * active concurrently. */
- int maxactive;
- /** Tracks the number of times the probed function's return was
- * ignored, due to maxactive being too low. */
- int nmissed;
- size_t data_size; /**< Instance data size */
- struct hlist_head free_instances; /**< Free instances list */
- struct hlist_head used_instances; /**< Used instances list */
-
-#ifdef CONFIG_ARM
- unsigned arm_noret:1; /**< No-return flag for ARM */
- unsigned thumb_noret:1; /**< No-return flag for Thumb */
-#endif
-};
-
-/**
- * @struct uretprobe_instance
- * @brief Structure for each uretprobe instance.
- */
-struct uretprobe_instance {
- /* either on free list or used list */
- struct hlist_node uflist; /**< Free list */
- struct hlist_node hlist; /**< Used list */
- struct uretprobe *rp; /**< Pointer to the parent uretprobe */
- kprobe_opcode_t *ret_addr; /**< Return address */
- kprobe_opcode_t *sp; /**< Pointer to stack */
- struct task_struct *task; /**< Pointer to the task struct */
-#ifdef CONFIG_ARM
- /* FIXME Preload: if this flag is set then ignore the thumb_mode(regs)
- * check in arch_prepare_uretprobe and use thumb trampoline. For the
- * moment we have to explicitly force arm mode when jumping to preload
- * handlers but we need the correct (i.e. original) retprobe tramp set
- * anyway. */
- int preload_thumb;
-#endif
- char data[0]; /**< Custom data */
-};
-
-int swap_register_uprobe(struct uprobe *p);
-void swap_unregister_uprobe(struct uprobe *p);
-void __swap_unregister_uprobe(struct uprobe *up, int disarm);
-
-int swap_register_ujprobe(struct ujprobe *jp);
-void swap_unregister_ujprobe(struct ujprobe *jp);
-void __swap_unregister_ujprobe(struct ujprobe *jp, int disarm);
-
-int swap_register_uretprobe(struct uretprobe *rp);
-void swap_unregister_uretprobe(struct uretprobe *rp);
-void __swap_unregister_uretprobe(struct uretprobe *rp, int disarm);
-
-void swap_unregister_all_uprobes(struct task_struct *task);
-
-void swap_ujprobe_return(void);
-struct kprobe *get_ukprobe(void *addr, pid_t tgid);
-struct kprobe *get_ukprobe_by_insn_slot(void *addr,
- pid_t tgid,
- struct pt_regs *regs);
-
-static inline struct uprobe *kp2up(struct kprobe *p)
-{
- return container_of(p, struct uprobe, kp);
-}
-
-static inline struct kprobe *up2kp(struct uprobe *p)
-{
- return &p->kp;
-}
-
-void disarm_uprobe(struct kprobe *p, struct task_struct *task);
-
-int trampoline_uprobe_handler(struct kprobe *p, struct pt_regs *regs);
-
-void add_uprobe_table(struct kprobe *p);
-
-#endif /* _SWAP_UPROBES_H */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_us_manager.o
-swap_us_manager-y := us_manager.o us_slot_manager.o helper.o debugfs_us_manager.o \
- sspt/ip.o sspt/sspt_page.o sspt/sspt_file.o sspt/sspt_proc.o \
- sspt/sspt_feature.o sspt/sspt_filter.o \
- pf/proc_filters.o pf/pf_group.o \
- img/img_proc.o img/img_file.o img/img_ip.o \
- probes/probes.o \
- probes/probe_info_new.o \
- callbacks.o
+++ /dev/null
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include "callbacks.h"
-
-static LIST_HEAD(cbs_list);
-static DEFINE_MUTEX(cbs_mutex);
-static int cur_handle = 0;
-
-struct cb_item {
- struct list_head list;
- enum callback_t type;
- int handle;
- void (*func)(void);
-};
-
-static inline void __lock_cbs_list(void)
-{
- mutex_lock(&cbs_mutex);
-}
-
-static inline void __unlock_cbs_list(void)
-{
- mutex_unlock(&cbs_mutex);
-}
-
-static inline int __get_new_handle(void)
-{
- return cur_handle++;
-}
-
-static inline void __free_cb(struct cb_item *cb)
-{
- list_del(&cb->list);
- kfree(cb);
-}
-
-static struct cb_item *__get_cb_by_handle(int handle)
-{
- struct cb_item *cb;
-
- list_for_each_entry(cb, &cbs_list, list)
- if (cb->handle == handle)
- return cb;
-
- return NULL;
-}
-
-
-/**
- * @brief Executes callbacks on start/stop
- *
- * @param cbt Callback type
- * @return Void
- */
-void exec_cbs(enum callback_t cbt)
-{
- struct cb_item *cb;
-
- __lock_cbs_list();
-
- list_for_each_entry(cb, &cbs_list, list)
- if (cb->type == cbt)
- cb->func();
-
- __unlock_cbs_list();
-}
-
-/**
- * @brief Removes all callbacks from list
- *
- * @return Void
- */
-void remove_all_cbs(void)
-{
- struct cb_item *cb, *n;
-
- __lock_cbs_list();
-
- list_for_each_entry_safe(cb, n, &cbs_list, list)
- __free_cb(cb);
-
- __unlock_cbs_list();
-}
-
-/**
- * @brief Registers callback on event
- *
- * @param cbt Callback type
- * @param func Callback function
- * @return Handle on succes, error code on error
- */
-int us_manager_reg_cb(enum callback_t cbt, void (*func)(void))
-{
- struct cb_item *cb;
- int handle;
-
- cb = kmalloc(sizeof(*cb), GFP_KERNEL);
- if (cb == NULL)
- return -ENOMEM;
-
- handle = __get_new_handle();
-
- INIT_LIST_HEAD(&cb->list);
- cb->type = cbt;
- cb->handle = handle;
- cb->func = func;
-
- __lock_cbs_list();
- list_add_tail(&cb->list, &cbs_list);
- __unlock_cbs_list();
-
- return handle;
-}
-EXPORT_SYMBOL_GPL(us_manager_reg_cb);
-
-/**
- * @brief Unegisters callback by handle
- *
- * @param handle Callback handle
- * @return Void
- */
-void us_manager_unreg_cb(int handle)
-{
- struct cb_item *cb;
-
- __lock_cbs_list();
-
- cb = __get_cb_by_handle(handle);
- if (cb == NULL)
- goto handle_not_found;
-
- __free_cb(cb);
-
-handle_not_found:
- __unlock_cbs_list();
-}
-EXPORT_SYMBOL_GPL(us_manager_unreg_cb);
+++ /dev/null
-#ifndef __CALLBACKS_H__
-#define __CALLBACKS_H__
-
-enum callback_t {
- START_CB = 0,
- STOP_CB,
- STOP_CB_TD
-};
-
-/* Gets callback type (on start or on stop) and function pointer.
- * Returns positive callback's handle that is used to unregister on success,
- * negative error code otherwise.
- * Exported function. */
-int us_manager_reg_cb(enum callback_t cbt, void (*func)(void));
-
-/* Gets handle and unregisters function with this handle.
- * Exported function. */
-void us_manager_unreg_cb(int handle);
-
-/* Used to execute callbacks when start/stop is occuring. */
-void exec_cbs(enum callback_t cbt);
-
-/* Removes all callbacks */
-void remove_all_cbs(void);
-
-#endif /* __CALLBACKS_H__ */
+++ /dev/null
-#include <linux/debugfs.h>
-#include <linux/module.h>
-
-#include <master/swap_debugfs.h>
-#include <master/swap_initializer.h>
-#include <us_manager/sspt/sspt_proc.h>
-
-#include "debugfs_us_manager.h"
-
-#define MAX_APPS_COUNT 8 /* According to daemon defenitions */
-#define PID_STRING 21 /* Maximum pid string = 20 (max digits count in
- * unsigned int on 64-bit arch) + 1 (for \n) */
-
-/* ============================================================================
- * = FOPS_TASKS =
- * ============================================================================
- */
-
-struct read_buf {
- char *begin;
- char *ptr;
- char *end;
-};
-
-static void on_each_proc_callback(struct sspt_proc *proc, void *data)
-{
- struct read_buf *rbuf = (struct read_buf *)data;
- char pid_str[PID_STRING];
- int len;
-
- /* skip process */
- if (!sspt_proc_is_send_event(proc))
- return;
-
- snprintf(pid_str, sizeof(pid_str), "%d", proc->tgid);
-
- len = strlen(pid_str);
-
- if (rbuf->end - rbuf->ptr < len + 2)
- return;
-
- memcpy(rbuf->ptr, pid_str, len);
- rbuf->ptr += len;
-
- *rbuf->ptr = ' ';
- ++rbuf->ptr;
-}
-
-static ssize_t read_tasks(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- char buf[PID_STRING * MAX_APPS_COUNT];
- struct read_buf rbuf = {
- .begin = buf,
- .ptr = buf,
- .end = buf + sizeof(buf)
- };
-
- on_each_proc_no_lock(on_each_proc_callback, (void *)&rbuf);
-
- if (rbuf.ptr != rbuf.begin)
- rbuf.ptr--;
-
- *rbuf.ptr = '\n';
-
- return simple_read_from_buffer(user_buf, count, ppos, rbuf.begin,
- rbuf.ptr - rbuf.begin);
-}
-
-static const struct file_operations fops_tasks = {
- .owner = THIS_MODULE,
- .open = swap_init_simple_open,
- .release = swap_init_simple_release,
- .read = read_tasks,
- .llseek = default_llseek
-};
-
-/* ============================================================================
- * = INIT/EXIT =
- * ============================================================================
- */
-
-static struct dentry *us_manager_dir;
-
-/**
- * @brief Destroy debugfs for us_manager
- *
- * @return Void
- */
-void exit_debugfs_us_manager(void)
-{
- if (us_manager_dir)
- debugfs_remove_recursive(us_manager_dir);
-
- us_manager_dir = NULL;
-}
-
-/**
- * @brief Create debugfs for us_manager
- *
- * @return Error code
- */
-int init_debugfs_us_manager(void)
-{
- struct dentry *swap_dir, *dentry;
-
- swap_dir = swap_debugfs_getdir();
- if (swap_dir == NULL)
- return -ENOENT;
-
- us_manager_dir = debugfs_create_dir(US_MANAGER_DFS_DIR, swap_dir);
- if (us_manager_dir == NULL)
- return -ENOMEM;
-
- dentry = debugfs_create_file(US_MANAGER_TASKS, 0600, us_manager_dir,
- NULL, &fops_tasks);
- if (dentry == NULL)
- goto fail;
-
- return 0;
-
-fail:
- exit_debugfs_us_manager();
- return -ENOMEM;
-}
+++ /dev/null
-#ifndef __DEBUGFS_US_MANAGER_H__
-#define __DEBUGFS_US_MANAGER_H__
-
-/**
- * @file us_manager/debugfs_us_manager.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2014
- */
-
-/**
- * @def US_MANAGER_DFS_DIR @hideinitializer
- * Name in debugfs
- */
-#define US_MANAGER_DFS_DIR "us_manager"
-
-/**
- * @def US_MANAGER_DFS_DIR @hideinitializer
- * Name in debugfs
- */
-#define US_MANAGER_TASKS "tasks"
-
-int init_debugfs_us_manager(void);
-void exit_debugfs_us_manager(void);
-
-#endif /* __DEBUGFS_US_MANAGER_H__ */
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/helper.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include <kprobe/swap_kprobes.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include <ksyms/ksyms.h>
-#include <writer/kernel_operations.h>
-#include "us_slot_manager.h"
-#include "sspt/sspt.h"
-#include "sspt/sspt_filter.h"
-#include "helper.h"
-
-struct task_struct;
-
-struct task_struct *check_task(struct task_struct *task);
-
-static atomic_t stop_flag = ATOMIC_INIT(0);
-
-
-/*
- ******************************************************************************
- * do_page_fault() *
- ******************************************************************************
- */
-
-struct pf_data {
- unsigned long addr;
-
-#if defined(CONFIG_ARM)
- struct pt_regs *pf_regs;
- unsigned long save_pc;
-#endif /* CONFIG_ARM */
-};
-
-static int entry_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
- struct pf_data *data = (struct pf_data *)ri->data;
-
-#if defined(CONFIG_ARM)
- data->addr = swap_get_karg(regs, 0);
- data->pf_regs = (struct pt_regs *)swap_get_karg(regs, 2);
- data->save_pc = data->pf_regs->ARM_pc;
-#elif defined(CONFIG_X86_32)
- data->addr = read_cr2();
-#else
- #error "this architecture is not supported"
-#endif /* CONFIG_arch */
-
- if (data->addr) {
- struct sspt_proc * proc = sspt_proc_get_by_task(current);
-
- if (proc && (proc->r_state_addr == data->addr))
- /* skip ret_handler_pf() for current task */
- return 1;
- }
-
- return 0;
-}
-
-static unsigned long cb_pf(void *data)
-{
- unsigned long page_addr = *(unsigned long *)data;
-
- call_page_fault(current, page_addr);
-
- return 0;
-}
-
-/* Detects when IPs are really loaded into phy mem and installs probes. */
-static int ret_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
- struct task_struct *task = current;
- struct pf_data *data = (struct pf_data *)ri->data;
- unsigned long page_addr;
- int ret;
-
- if (is_kthread(task))
- return 0;
-
-#if defined(CONFIG_ARM)
- /* skip fixup page_fault */
- if (data->save_pc != data->pf_regs->ARM_pc)
- return 0;
-#endif /* CONFIG_ARM */
-
- /* TODO: check return value */
- page_addr = data->addr & PAGE_MASK;
- ret = set_jump_cb((unsigned long)ri->ret_addr, regs, cb_pf,
- &page_addr, sizeof(page_addr));
-
- if (ret == 0)
- ri->ret_addr = (unsigned long *)get_jump_addr();
-
- return 0;
-}
-
-static struct kretprobe mf_kretprobe = {
- .entry_handler = entry_handler_pf,
- .handler = ret_handler_pf,
- .data_size = sizeof(struct pf_data)
-};
-
-static int register_mf(void)
-{
- int ret;
-
- ret = swap_register_kretprobe(&mf_kretprobe);
- if (ret)
- printk(KERN_INFO "swap_register_kretprobe(handle_mm_fault) ret=%d!\n",
- ret);
-
- return ret;
-}
-
-static void unregister_mf(void)
-{
- swap_unregister_kretprobe(&mf_kretprobe);
-}
-
-
-
-
-
-#ifdef CONFIG_ARM
-/*
- ******************************************************************************
- * workaround for already running *
- ******************************************************************************
- */
-static unsigned long cb_check_and_install(void *data);
-
-static int ctx_task_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
- int ret;
- struct sspt_proc *proc;
- struct task_struct *task = current;
-
- if (is_kthread(task) || check_task_on_filters(task) == 0)
- return 0;
-
- proc = sspt_proc_get_by_task(task);
- if (proc && proc->first_install)
- return 0;
-
- ret = set_kjump_cb(regs, cb_check_and_install, NULL, 0);
- if (ret < 0)
- pr_err("ctx_task_pre_handler: ret=%d\n", ret);
-
- return 0;
-}
-
-static struct kprobe ctx_task_kprobe = {
- .pre_handler = ctx_task_pre_handler,
-};
-
-static int register_ctx_task(void)
-{
- int ret = 0;
-
- ret = swap_register_kprobe(&ctx_task_kprobe);
- if (ret)
- printk(KERN_INFO "swap_register_kprobe(workaround) ret=%d!\n",
- ret);
-
- return ret;
-}
-
-static void unregister_ctx_task(void)
-{
- swap_unregister_kprobe(&ctx_task_kprobe);
-}
-#endif /* CONFIG_ARM */
-
-
-
-
-
-/*
- ******************************************************************************
- * copy_process() *
- ******************************************************************************
- */
-static void func_uinst_creare(struct us_ip *ip, void *data)
-{
- struct hlist_head *head = (struct hlist_head *)data;
- struct uprobe *up;
-
- up = probe_info_get_uprobe(ip->info, ip);
- if (up) {
- struct uinst_info *uinst;
- unsigned long vaddr = (unsigned long)up->kp.addr;
-
- uinst = uinst_info_create(vaddr, up->kp.opcode);
- if (uinst)
- hlist_add_head(&uinst->hlist, head);
- }
-}
-
-static void disarm_for_task(struct task_struct *child, struct hlist_head *head)
-{
- struct uinst_info *uinst;
- struct hlist_node *tmp;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- swap_hlist_for_each_entry_safe(uinst, node, tmp, head, hlist) {
- uinst_info_disarm(uinst, child);
- hlist_del(&uinst->hlist);
- uinst_info_destroy(uinst);
- }
-}
-
-struct clean_data {
- struct task_struct *task;
-
- struct hlist_head head;
- struct hlist_head rhead;
-};
-
-static atomic_t rm_uprobes_child_cnt = ATOMIC_INIT(0);
-
-static unsigned long cb_clean_child(void *data)
-{
- struct clean_data *cdata = (struct clean_data *)data;
- struct task_struct *child = cdata->task;
-
- /* disarm up for child */
- disarm_for_task(child, &cdata->head);
-
- /* disarm urp for child */
- urinst_info_put_current_hlist(&cdata->rhead, child);
-
- atomic_dec(&rm_uprobes_child_cnt);
- return 0;
-}
-
-static void rm_uprobes_child(struct kretprobe_instance *ri,
- struct pt_regs *regs, struct task_struct *child)
-{
- struct sspt_proc *proc;
- struct clean_data cdata = {
- .task = child,
- .head = HLIST_HEAD_INIT,
- .rhead = HLIST_HEAD_INIT
- };
-
- sspt_proc_write_lock();
- proc = sspt_proc_get_by_task_no_lock(current);
- if (proc) {
- sspt_proc_on_each_ip(proc, func_uinst_creare, (void *)&cdata.head);
- urinst_info_get_current_hlist(&cdata.rhead, false);
- }
- sspt_proc_write_unlock();
-
- if (proc) {
- int ret;
-
- /* set jumper */
- ret = set_jump_cb((unsigned long)ri->ret_addr, regs,
- cb_clean_child, &cdata, sizeof(cdata));
- if (ret == 0) {
- atomic_inc(&rm_uprobes_child_cnt);
- ri->ret_addr = (unsigned long *)get_jump_addr();
- }
- }
-}
-
-
-static atomic_t pre_handler_cp_cnt = ATOMIC_INIT(0);
-
-static unsigned long cp_cb(void *data)
-{
- if (atomic_read(&stop_flag))
- call_mm_release(current);
-
- atomic_dec(&pre_handler_cp_cnt);
- return 0;
-}
-
-static int pre_handler_cp(struct kprobe *p, struct pt_regs *regs)
-{
- int ret = 0;
-
- if (is_kthread(current))
- goto out;
-
- if (!atomic_read(&stop_flag))
- goto out;
-
- ret = set_kjump_cb(regs, cp_cb, NULL, 0);
- if (ret < 0) {
- pr_err("set_kjump_cp, ret=%d\n", ret);
- ret = 0;
- } else {
- atomic_inc(&pre_handler_cp_cnt);
- }
-out:
- return ret;
-}
-
-
-static atomic_t copy_process_cnt = ATOMIC_INIT(0);
-
-static int entry_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
- atomic_inc(©_process_cnt);
-
- return 0;
-}
-
-/* Delete uprobs in children at fork */
-static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
- struct task_struct *task =
- (struct task_struct *)regs_return_value(regs);
-
- if (!task || IS_ERR(task))
- goto out;
-
- if (task->mm != current->mm) { /* check flags CLONE_VM */
- rm_uprobes_child(ri, regs, task);
- }
-out:
- atomic_dec(©_process_cnt);
-
- return 0;
-}
-
-static struct kretprobe cp_kretprobe = {
- .entry_handler = entry_handler_cp,
- .handler = ret_handler_cp,
-};
-
-static struct kprobe cp_kprobe = {
- .pre_handler = pre_handler_cp
-};
-
-static int register_cp(void)
-{
- int ret;
-
-
- ret = swap_register_kprobe(&cp_kprobe);
- if (ret)
- pr_err("swap_register_kprobe(copy_process) ret=%d!\n", ret);
-
- ret = swap_register_kretprobe(&cp_kretprobe);
- if (ret) {
- pr_err("swap_register_kretprobe(copy_process) ret=%d!\n", ret);
- swap_unregister_kprobe(&cp_kprobe);
- }
-
- return ret;
-}
-
-static void unregister_cp(void)
-{
- swap_unregister_kretprobe_top(&cp_kretprobe, 0);
- do {
- synchronize_sched();
- } while (atomic_read(©_process_cnt));
- swap_unregister_kretprobe_bottom(&cp_kretprobe);
- swap_unregister_kprobe(&cp_kprobe);
-
- do {
- synchronize_sched();
- } while (atomic_read(&rm_uprobes_child_cnt)
- || atomic_read(&pre_handler_cp_cnt));
-}
-
-
-
-
-
-/*
- ******************************************************************************
- * mm_release() *
- ******************************************************************************
- */
-
-static atomic_t mm_release_cnt = ATOMIC_INIT(0);
-
-static unsigned long mr_cb(void *data)
-{
- struct task_struct *task = *(struct task_struct **)data;
- struct mm_struct *mm = task->mm;
-
- if (mm == NULL) {
- pr_err("mm is NULL\n");
- return 0;
- }
-
- /* TODO: this lock for synchronizing to disarm urp */
- down_write(&mm->mmap_sem);
- if (task->tgid != task->pid) {
- struct sspt_proc *proc;
- struct hlist_head head = HLIST_HEAD_INIT;
-
- if (task != current) {
- pr_err("call mm_release in isn't current context\n");
- return 0;
- }
-
- /* if the thread is killed we need to discard pending
- * uretprobe instances which have not triggered yet */
- sspt_proc_write_lock();
- proc = sspt_proc_get_by_task_no_lock(task);
- if (proc) {
- urinst_info_get_current_hlist(&head, true);
- }
- sspt_proc_write_unlock();
-
- if (proc) {
- /* disarm urp for task */
- urinst_info_put_current_hlist(&head, task);
- }
- } else {
- call_mm_release(task);
- }
- up_write(&mm->mmap_sem);
-
- atomic_dec(&mm_release_cnt);
-
- return 0;
-}
-
-/* Detects when target process removes IPs. */
-static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
- int ret = 0;
- struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
-
- if (is_kthread(task))
- goto out;
-
- ret = set_kjump_cb(regs, mr_cb, (void *)&task, sizeof(task));
- if (ret < 0) {
- printk("##### ERROR: mr_pre_handler, ret=%d\n", ret);
- ret = 0;
- } else {
- atomic_inc(&mm_release_cnt);
- }
-
-out:
- return ret;
-}
-
-static struct kprobe mr_kprobe = {
- .pre_handler = mr_pre_handler
-};
-
-static int register_mr(void)
-{
- int ret;
-
- ret = swap_register_kprobe(&mr_kprobe);
- if (ret)
- printk(KERN_INFO
- "swap_register_kprobe(mm_release) ret=%d!\n", ret);
-
- return ret;
-}
-
-static void unregister_mr(void)
-{
- swap_unregister_kprobe(&mr_kprobe);
- do {
- synchronize_sched();
- } while (atomic_read(&mm_release_cnt));
-}
-
-
-
-
-
-/*
- ******************************************************************************
- * do_munmap() *
- ******************************************************************************
- */
-struct unmap_data {
- unsigned long start;
- size_t len;
-};
-
-static atomic_t unmap_cnt = ATOMIC_INIT(0);
-
-struct msg_unmap_data {
- unsigned long start;
- unsigned long end;
-};
-
-static void msg_unmap(struct sspt_filter *f, void *data)
-{
- if (f->pfg_is_inst) {
- struct pfg_msg_cb *cb = pfg_msg_cb_get(f->pfg);
-
- if (cb && cb->msg_unmap) {
- struct msg_unmap_data *msg_data;
-
- msg_data = (struct msg_unmap_data *)data;
- cb->msg_unmap(msg_data->start, msg_data->end);
- }
- }
-}
-
-static void __remove_unmap_probes(struct sspt_proc *proc,
- struct unmap_data *umd)
-{
- struct task_struct *task = proc->task;
- unsigned long start = umd->start;
- size_t len = PAGE_ALIGN(umd->len);
- LIST_HEAD(head);
-
- if (sspt_proc_get_files_by_region(proc, &head, start, len)) {
- struct sspt_file *file, *n;
- unsigned long end = start + len;
- struct msg_unmap_data msg_data = {
- .start = start,
- .end = end
- };
-
- list_for_each_entry_safe(file, n, &head, list) {
- if (file->vm_start >= end)
- continue;
-
- if (file->vm_start >= start)
- sspt_file_uninstall(file, task, US_UNINSTALL);
- /* TODO: else: uninstall pages: * start..file->vm_end */
- }
-
- sspt_proc_insert_files(proc, &head);
-
- sspt_proc_on_each_filter(proc, msg_unmap, (void *)&msg_data);
- }
-}
-
-static void remove_unmap_probes(struct task_struct *task,
- struct unmap_data *umd)
-{
- struct sspt_proc *proc;
-
- sspt_proc_write_lock();
-
- proc = sspt_proc_get_by_task_no_lock(task);
- if (proc)
- __remove_unmap_probes(proc, umd);
-
- sspt_proc_write_unlock();
-}
-
-static int entry_handler_unmap(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct unmap_data *data = (struct unmap_data *)ri->data;
- struct task_struct *task = current->group_leader;
-
- atomic_inc(&unmap_cnt);
-
- data->start = swap_get_karg(regs, 1);
- data->len = (size_t)swap_get_karg(regs, 2);
-
- if (!is_kthread(task) && atomic_read(&stop_flag))
- remove_unmap_probes(task, data);
-
- return 0;
-}
-
-static int ret_handler_unmap(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct task_struct *task;
-
- task = current->group_leader;
- if (is_kthread(task) || regs_return_value(regs))
- goto out;
-
- remove_unmap_probes(task, (struct unmap_data *)ri->data);
-
-out:
- atomic_dec(&unmap_cnt);
-
- return 0;
-}
-
-static struct kretprobe unmap_kretprobe = {
- .entry_handler = entry_handler_unmap,
- .handler = ret_handler_unmap,
- .data_size = sizeof(struct unmap_data)
-};
-
-static int register_unmap(void)
-{
- int ret;
-
- ret = swap_register_kretprobe(&unmap_kretprobe);
- if (ret)
- printk(KERN_INFO "swap_register_kprobe(do_munmap) ret=%d!\n",
- ret);
-
- return ret;
-}
-
-static void unregister_unmap(void)
-{
- swap_unregister_kretprobe_top(&unmap_kretprobe, 0);
- do {
- synchronize_sched();
- } while (atomic_read(&unmap_cnt));
- swap_unregister_kretprobe_bottom(&unmap_kretprobe);
-}
-
-
-
-
-
-/*
- ******************************************************************************
- * do_mmap_pgoff() *
- ******************************************************************************
- */
-static void msg_map(struct sspt_filter *f, void *data)
-{
- if (f->pfg_is_inst) {
- struct pfg_msg_cb *cb = pfg_msg_cb_get(f->pfg);
-
- if (cb && cb->msg_map)
- cb->msg_map((struct vm_area_struct *)data);
- }
-}
-
-static int ret_handler_mmap(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct sspt_proc *proc;
- struct task_struct *task;
- unsigned long start_addr;
- struct vm_area_struct *vma;
-
- task = current->group_leader;
- if (is_kthread(task))
- return 0;
-
- start_addr = regs_return_value(regs);
- if (IS_ERR_VALUE(start_addr))
- return 0;
-
- proc = sspt_proc_get_by_task(task);
- if (proc == NULL)
- return 0;
-
- vma = find_vma_intersection(task->mm, start_addr, start_addr + 1);
- if (vma && check_vma(vma))
- sspt_proc_on_each_filter(proc, msg_map, (void *)vma);
-
- return 0;
-}
-
-static struct kretprobe mmap_kretprobe = {
- .handler = ret_handler_mmap
-};
-
-static int register_mmap(void)
-{
- int ret;
-
- ret = swap_register_kretprobe(&mmap_kretprobe);
- if (ret)
- printk(KERN_INFO "swap_register_kretprobe(do_mmap_pgoff) ret=%d!\n",
- ret);
-
- return ret;
-}
-
-static void unregister_mmap(void)
-{
- swap_unregister_kretprobe(&mmap_kretprobe);
-}
-
-
-
-
-
-/*
- ******************************************************************************
- * set_task_comm() *
- ******************************************************************************
- */
-struct comm_data {
- struct task_struct *task;
-};
-
-static unsigned long cb_check_and_install(void *data)
-{
- check_task_and_install(current);
-
- return 0;
-}
-
-static int entry_handler_comm(struct kretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct comm_data *data = (struct comm_data *)ri->data;
-
- data->task = (struct task_struct *)swap_get_karg(regs, 0);
-
- return 0;
-}
-
-static int ret_handler_comm(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
- struct task_struct *task;
- int ret;
-
- if (is_kthread(current))
- return 0;
-
- task = ((struct comm_data *)ri->data)->task;
- if (task != current)
- return 0;
-
- ret = set_jump_cb((unsigned long)ri->ret_addr, regs,
- cb_check_and_install, NULL, 0);
- if (ret == 0)
- ri->ret_addr = (unsigned long *)get_jump_addr();
-
- return 0;
-}
-
-static struct kretprobe comm_kretprobe = {
- .entry_handler = entry_handler_comm,
- .handler = ret_handler_comm,
- .data_size = sizeof(struct comm_data)
-};
-
-static int register_comm(void)
-{
- int ret;
-
- ret = swap_register_kretprobe(&comm_kretprobe);
- if (ret)
- printk(KERN_INFO "swap_register_kretprobe(set_task_comm) ret=%d!\n",
- ret);
-
- return ret;
-}
-
-static void unregister_comm(void)
-{
- swap_unregister_kretprobe(&comm_kretprobe);
-}
-
-
-
-
-
-/**
- * @brief Registration of helper
- *
- * @return Error code
- */
-int register_helper(void)
-{
- int ret = 0;
-
- atomic_set(&stop_flag, 0);
-
- /*
- * install probe on 'set_task_comm' to detect when field comm struct
- * task_struct changes
- */
- ret = register_comm();
- if (ret)
- return ret;
-
- /* install probe on 'do_munmap' to detect when for remove US probes */
- ret = register_unmap();
- if (ret)
- goto unreg_comm;
-
- /* install probe on 'mm_release' to detect when for remove US probes */
- ret = register_mr();
- if (ret)
- goto unreg_unmap;
-
- /* install probe on 'copy_process' to disarm children process */
- ret = register_cp();
- if (ret)
- goto unreg_mr;
-
- /* install probe on 'do_mmap_pgoff' to detect when mapping file */
- ret = register_mmap();
- if (ret)
- goto unreg_cp;
-
- /*
- * install probe on 'handle_mm_fault' to detect when US pages will be
- * loaded
- */
- ret = register_mf();
- if (ret)
- goto unreg_mmap;
-
-#ifdef CONFIG_ARM
- /* install probe to detect already running process */
- ret = register_ctx_task();
- if (ret)
- goto unreg_mf;
-#endif /* CONFIG_ARM */
-
- return ret;
-
-#ifdef CONFIG_ARM
-unreg_mf:
- unregister_mf();
-#endif /* CONFIG_ARM */
-
-unreg_mmap:
- unregister_mmap();
-
-unreg_cp:
- unregister_cp();
-
-unreg_mr:
- unregister_mr();
-
-unreg_unmap:
- unregister_unmap();
-
-unreg_comm:
- unregister_comm();
-
- return ret;
-}
-
-/**
- * @brief Unegistration of helper bottom
- *
- * @return Void
- */
-void unregister_helper_top(void)
-{
-#ifdef CONFIG_ARM
- unregister_ctx_task();
-#endif /* CONFIG_ARM */
- unregister_mf();
- atomic_set(&stop_flag, 1);
-}
-
-/**
- * @brief Unegistration of helper top
- *
- * @return Void
- */
-void unregister_helper_bottom(void)
-{
- unregister_mmap();
- unregister_cp();
- unregister_mr();
- unregister_unmap();
- unregister_comm();
-}
-
-/**
- * @brief Initialization of helper
- *
- * @return Error code
- */
-int once_helper(void)
-{
- const char *sym;
-
- sym = "do_page_fault";
- mf_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
- if (mf_kretprobe.kp.addr == NULL)
- goto not_found;
-
- sym = "copy_process";
- cp_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms_substr(sym);
- if (cp_kretprobe.kp.addr == NULL)
- goto not_found;
- cp_kprobe.addr = cp_kretprobe.kp.addr;
-
- sym = "mm_release";
- mr_kprobe.addr = (kprobe_opcode_t *)swap_ksyms(sym);
- if (mr_kprobe.addr == NULL)
- goto not_found;
-
- sym = "do_munmap";
- unmap_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
- if (unmap_kretprobe.kp.addr == NULL)
- goto not_found;
-
- sym = "do_mmap_pgoff";
- mmap_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
- if (mmap_kretprobe.kp.addr == NULL)
- goto not_found;
-
- sym = "set_task_comm";
- comm_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
- if (comm_kretprobe.kp.addr == NULL)
- goto not_found;
-
-#ifdef CONFIG_ARM
- sym = "ret_to_user";
- ctx_task_kprobe.addr = (kprobe_opcode_t *)swap_ksyms(sym);
- if (ctx_task_kprobe.addr == NULL)
- goto not_found;
-#endif /* CONFIG_ARM */
-
- return 0;
-
-not_found:
- printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
- return -ESRCH;
-}
+++ /dev/null
-/**
- * @file us_manager/helper.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-#ifndef _HELPER_H
-#define _HELPER_H
-
-#include <linux/sched.h>
-
-static inline int is_kthread(struct task_struct *task)
-{
- return !task->mm;
-}
-
-int once_helper(void);
-
-int register_helper(void);
-void unregister_helper_top(void);
-void unregister_helper_bottom(void);
-
-#endif /* _HELPER_H */
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/img/img_file.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include "img_file.h"
-#include "img_ip.h"
-#include <linux/slab.h>
-#include <linux/dcache.h>
-
-
-static void img_del_ip_by_list(struct img_ip *ip);
-
-/**
- * @brief Create img_file struct
- *
- * @param dentry Dentry of file
- * @return Pointer to the created img_file struct
- */
-struct img_file *create_img_file(struct dentry *dentry)
-{
- struct img_file *file;
-
- file = kmalloc(sizeof(*file), GFP_ATOMIC);
- if (file == NULL) {
- pr_err("%s: failed to allocate memory\n", __func__);
- return NULL;
- }
-
- file->dentry = dentry;
- INIT_LIST_HEAD(&file->ip_list);
- INIT_LIST_HEAD(&file->list);
-
- return file;
-}
-
-/**
- * @brief Remove img_file struct
- *
- * @param file remove object
- * @return Void
- */
-void free_img_file(struct img_file *file)
-{
- struct img_ip *ip, *tmp;
-
- list_for_each_entry_safe(ip, tmp, &file->ip_list, list) {
- img_del_ip_by_list(ip);
- free_img_ip(ip);
- }
-
- kfree(file);
-}
-
-static void img_add_ip_by_list(struct img_file *file, struct img_ip *ip)
-{
- list_add(&ip->list, &file->ip_list);
-}
-
-static void img_del_ip_by_list(struct img_ip *ip)
-{
- list_del(&ip->list);
-}
-
-static struct img_ip *find_img_ip(struct img_file *file, unsigned long addr)
-{
- struct img_ip *ip;
-
- list_for_each_entry(ip, &file->ip_list, list) {
- if (ip->addr == addr)
- return ip;
- }
-
- return NULL;
-}
-
-/**
- * @brief Add instrumentation pointer
- *
- * @param file Pointer to the img_file struct
- * @param addr Function address
- * @param probe_Pointer to a probe_info structure with an information about
- * the probe.
- * @return Error code
- */
-int img_file_add_ip(struct img_file *file, unsigned long addr,
- struct probe_info *probe_i)
-{
- struct img_ip *ip;
-
- ip = find_img_ip(file, addr);
- if (ip) {
- /* ip already exists in img */
- return 0;
- }
-
- ip = create_img_ip(addr, probe_i);
- if (ip == NULL)
- return -ENOMEM;
-
- img_add_ip_by_list(file, ip);
-
- return 0;
-}
-
-/**
- * @brief Delete img_ip struct from img_file struct
- *
- * @param file Pointer to the img_file struct
- * @param addr Function address
- * @return Error code
- */
-int img_file_del_ip(struct img_file *file, unsigned long addr)
-{
- struct img_ip *ip;
-
- ip = find_img_ip(file, addr);
- if (ip == NULL) {
- printk(KERN_INFO "Warning: no ip found in img, addr = %lx\n",
- addr);
- return -EINVAL;
- }
-
- img_del_ip_by_list(ip);
-
- return 0;
-}
-
-/**
- * @brief Check on absence img_ip structs in img_file struct
- *
- * @param file Pointer to the img_file struct
- * @return
- * - 0 - not empty
- * - 1 - empty
- */
-int img_file_empty(struct img_file *file)
-{
- return list_empty(&file->ip_list);
-}
-
-/**
- * @brief For debug
- *
- * @param file Pointer to the img_file struct
- * @return Void
- */
-
-/* debug */
-void img_file_print(struct img_file *file)
-{
- struct img_ip *ip;
-
- printk(KERN_INFO "### d_iname=%s\n", file->dentry->d_iname);
-
- list_for_each_entry(ip, &file->ip_list, list) {
- img_ip_print(ip);
- }
-}
-/* debug */
+++ /dev/null
-/**
- * @file us_manager/img/img_file.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- *
- */
-
-
-#ifndef _IMG_FILE_H
-#define _IMG_FILE_H
-
-#include <linux/types.h>
-
-struct probe_info;
-
-/**
- * @struct img_file
- * @breaf Image of file
- */
-struct img_file {
- struct list_head list; /**< For img_proc */
- struct dentry *dentry; /**< Dentry of file */
- struct list_head ip_list; /**< For img_ip */
-};
-
-struct img_file *create_img_file(struct dentry *dentry);
-void free_img_file(struct img_file *ip);
-
-int img_file_add_ip(struct img_file *file, unsigned long addr,
- struct probe_info *probe_i);
-int img_file_del_ip(struct img_file *file, unsigned long addr);
-
-int img_file_empty(struct img_file *file);
-
-/* debug */
-void img_file_print(struct img_file *file);
-/* debug */
-
-#endif /* _IMG_FILE_H */
-
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/img/img_ip.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include "img_ip.h"
-#include <us_manager/probes/use_probes.h>
-#include <linux/slab.h>
-
-/**
- * @brief Create img_ip struct
- *
- * @param addr Function address
- * @param probe_i Pointer to the probe info data.
- * @return Pointer to the created img_ip struct
- */
-struct img_ip *create_img_ip(unsigned long addr, struct probe_info *info)
-{
- struct img_ip *ip;
-
- ip = kmalloc(sizeof(*ip), GFP_ATOMIC);
- if (ip) {
- struct probe_info *info_new;
-
- info_new = probe_info_dup(info);
- if (info_new == NULL) {
- kfree(ip);
- return NULL;
- }
-
- probe_info_copy(info, info_new);
-
- INIT_LIST_HEAD(&ip->list);
- ip->addr = addr;
- ip->info = info_new;
- }
-
- return ip;
-}
-
-/**
- * @brief Remove img_ip struct
- *
- * @param ip remove object
- * @return Void
- */
-void free_img_ip(struct img_ip *ip)
-{
- probe_info_cleanup(ip->info);
- probe_info_free(ip->info);
- kfree(ip);
-}
-
-/**
- * @brief For debug
- *
- * @param ip Pointer to the img_ip struct
- * @return Void
- */
-
-/* debug */
-void img_ip_print(struct img_ip *ip)
-{
- if (ip->info->probe_type == SWAP_RETPROBE)
- printk(KERN_INFO "### addr=8%lx, args=%s\n",
- ip->addr, ip->info->rp_i.args);
-}
-/* debug */
+++ /dev/null
-/**
- * @file us_manager/img/img_ip.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- *
- */
-
-
-#ifndef _IMG_IP_H
-#define _IMG_IP_H
-
-#include <linux/types.h>
-#include <us_manager/probes/probes.h>
-
-/**
- * @struct img_ip
- * @breaf Image of instrumentation pointer
- */
-struct img_ip {
- struct list_head list; /**< For img_file */
- unsigned long addr; /**< Function address */
- struct probe_info *info; /**< Probe info */
-};
-
-struct img_ip *create_img_ip(unsigned long addr, struct probe_info *info);
-void free_img_ip(struct img_ip *ip);
-
-/* debug */
-void img_ip_print(struct img_ip *ip);
-/* debug */
-
-#endif /* _IMG_IP_H */
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/img/img_proc.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/sspt/sspt_file.h>
-#include "img_ip.h"
-#include "img_proc.h"
-#include "img_file.h"
-
-
-struct img_proc {
- struct list_head file_list;
- rwlock_t rwlock;
-};
-
-
-static void img_del_file_by_list(struct img_file *file);
-
-/**
- * @brief Create img_proc struct
- *
- * @return Pointer to the created img_proc struct
- */
-struct img_proc *create_img_proc(void)
-{
- struct img_proc *proc;
-
- proc = kmalloc(sizeof(*proc), GFP_ATOMIC);
- if (proc) {
- INIT_LIST_HEAD(&proc->file_list);
- rwlock_init(&proc->rwlock);
- }
-
- return proc;
-}
-
-/**
- * @brief Remove img_proc struct
- *
- * @param file remove object
- * @return Void
- */
-void free_img_proc(struct img_proc *proc)
-{
- struct img_file *file, *tmp;
-
- list_for_each_entry_safe(file, tmp, &proc->file_list, list) {
- img_del_file_by_list(file);
- free_img_file(file);
- }
-
- kfree(proc);
-}
-
-/* called with write_[lock/unlock](&proc->rwlock) */
-static void img_add_file_by_list(struct img_proc *proc, struct img_file *file)
-{
- list_add(&file->list, &proc->file_list);
-}
-
-/* called with write_[lock/unlock](&proc->rwlock) */
-static void img_del_file_by_list(struct img_file *file)
-{
- list_del(&file->list);
-}
-
-/* called with read_[lock/unlock](&proc->rwlock) */
-static struct img_file *find_img_file(struct img_proc *proc,
- struct dentry *dentry)
-{
- struct img_file *file;
-
- list_for_each_entry(file, &proc->file_list, list) {
- if (file->dentry == dentry)
- return file;
- }
-
- return NULL;
-}
-
-/**
- * @brief Add instrumentation pointer
- *
- * @param proc Pointer to the img_proc struct
- * @param dentry Dentry of file
- * @param addr Function address
- * @param probe_i Pointer to a probe_info struct related with the probe
- * @return Error code
- */
-int img_proc_add_ip(struct img_proc *proc, struct dentry *dentry,
- unsigned long addr, struct probe_info *probe_i)
-{
- int ret;
- struct img_file *file;
-
- write_lock(&proc->rwlock);
- file = find_img_file(proc, dentry);
- if (file) {
- ret = img_file_add_ip(file, addr, probe_i);
- goto unlock;
- }
-
- file = create_img_file(dentry);
- if (file == NULL) {
- ret = -ENOMEM;
- goto unlock;
- }
-
- ret = img_file_add_ip(file, addr, probe_i);
- if (ret) {
- printk(KERN_INFO "Cannot add ip to img file\n");
- free_img_file(file);
- } else {
- img_add_file_by_list(proc, file);
- }
-
-unlock:
- write_unlock(&proc->rwlock);
- return ret;
-}
-
-/**
- * @brief Remove instrumentation pointer
- *
- * @param proc Pointer to the img_proc struct
- * @param dentry Dentry of file
- * @param args Function address
- * @return Error code
- */
-int img_proc_del_ip(struct img_proc *proc,
- struct dentry *dentry,
- unsigned long addr)
-{
- int ret;
- struct img_file *file;
-
- write_lock(&proc->rwlock);
- file = find_img_file(proc, dentry);
- if (file == NULL) {
- ret = -EINVAL;
- goto unlock;
- }
-
- ret = img_file_del_ip(file, addr);
- if (ret == 0 && img_file_empty(file)) {
- img_del_file_by_list(file);
- free_img_file(file);
- }
-
-unlock:
- write_unlock(&proc->rwlock);
- return ret;
-}
-
-void img_proc_copy_to_sspt(struct img_proc *i_proc, struct sspt_proc *proc)
-{
- struct sspt_file *file;
- struct img_file *i_file;
-
- read_lock(&i_proc->rwlock);
- list_for_each_entry(i_file, &i_proc->file_list, list) {
- file = sspt_proc_find_file_or_new(proc, i_file->dentry);
-
- if (file) {
- struct img_ip *i_ip;
-
- list_for_each_entry(i_ip, &i_file->ip_list, list)
- sspt_file_add_ip(file, i_ip->addr, i_ip->info);
- }
- }
- read_unlock(&i_proc->rwlock);
-}
-
-/**
- * @brief For debug
- *
- * @param proc Pointer to the img_proc struct
- * @return Void
- */
-
-/* debug */
-void img_proc_print(struct img_proc *proc)
-{
- struct img_file *file;
-
- printk(KERN_INFO "### img_proc_print:\n");
-
- read_lock(&proc->rwlock);
- list_for_each_entry(file, &proc->file_list, list) {
- img_file_print(file);
- }
- read_unlock(&proc->rwlock);
-}
-/* debug */
+++ /dev/null
-/**
- * @file us_manager/img/img_proc.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENCE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-
-#ifndef _IMG_PROC_H
-#define _IMG_PROC_H
-
-#include <linux/types.h>
-
-struct dentry;
-struct sspt_proc;
-struct probe_info;
-
-
-struct img_proc *create_img_proc(void);
-void free_img_proc(struct img_proc *proc);
-
-int img_proc_add_ip(struct img_proc *proc, struct dentry *dentry,
- unsigned long addr, struct probe_info *probe_i);
-int img_proc_del_ip(struct img_proc *proc,
- struct dentry *dentry,
- unsigned long addr);
-
-void img_proc_copy_to_sspt(struct img_proc *i_proc, struct sspt_proc *proc);
-
-/* debug */
-void img_proc_print(struct img_proc *proc);
-/* debug */
-
-#endif /* _IMG_PROC_H */
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/pf/pf_group.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/namei.h>
-#include <linux/mman.h>
-#include <linux/spinlock.h>
-#include "pf_group.h"
-#include "proc_filters.h"
-#include "../sspt/sspt_filter.h"
-#include "../us_manager_common.h"
-#include <us_manager/img/img_proc.h>
-#include <us_manager/img/img_file.h>
-#include <us_manager/img/img_ip.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include <us_manager/helper.h>
-
-struct pf_group {
- struct list_head list;
- struct img_proc *i_proc;
- struct proc_filter filter;
- struct pfg_msg_cb *msg_cb;
- atomic_t usage;
-
- spinlock_t pl_lock; /* for proc_list */
- struct list_head proc_list;
-};
-
-struct pl_struct {
- struct list_head list;
- struct sspt_proc *proc;
-};
-
-static LIST_HEAD(pfg_list);
-static DEFINE_RWLOCK(pfg_list_lock);
-
-/* struct pl_struct */
-static struct pl_struct *create_pl_struct(struct sspt_proc *proc)
-{
- struct pl_struct *pls = kmalloc(sizeof(*pls), GFP_ATOMIC);
-
- if (pls) {
- INIT_LIST_HEAD(&pls->list);
- pls->proc = sspt_proc_get(proc);
- }
-
- return pls;
-}
-
-static void free_pl_struct(struct pl_struct *pls)
-{
- sspt_proc_put(pls->proc);
- kfree(pls);
-}
-/* struct pl_struct */
-
-static struct pf_group *pfg_create(void)
-{
- struct pf_group *pfg = kmalloc(sizeof(*pfg), GFP_ATOMIC);
-
- if (pfg == NULL)
- return NULL;
-
- pfg->i_proc = create_img_proc();
- if (pfg->i_proc == NULL)
- goto create_pfg_fail;
-
- INIT_LIST_HEAD(&pfg->list);
- memset(&pfg->filter, 0, sizeof(pfg->filter));
- spin_lock_init(&pfg->pl_lock);
- INIT_LIST_HEAD(&pfg->proc_list);
- pfg->msg_cb = NULL;
- atomic_set(&pfg->usage, 1);
-
- return pfg;
-
-create_pfg_fail:
-
- kfree(pfg);
-
- return NULL;
-}
-
-static void pfg_free(struct pf_group *pfg)
-{
- struct pl_struct *pl, *n;
-
- free_img_proc(pfg->i_proc);
- free_pf(&pfg->filter);
- list_for_each_entry_safe(pl, n, &pfg->proc_list, list) {
- sspt_proc_del_filter(pl->proc, pfg);
- free_pl_struct(pl);
- }
-
- kfree(pfg);
-}
-
-static int pfg_add_proc(struct pf_group *pfg, struct sspt_proc *proc)
-{
- struct pl_struct *pls;
-
- pls = create_pl_struct(proc);
- if (pls == NULL)
- return -ENOMEM;
-
- spin_lock(&pfg->pl_lock);
- list_add(&pls->list, &pfg->proc_list);
- spin_unlock(&pfg->pl_lock);
-
- return 0;
-}
-
-
-/* called with pfg_list_lock held */
-static void pfg_add_to_list(struct pf_group *pfg)
-{
- list_add(&pfg->list, &pfg_list);
-}
-
-/* called with pfg_list_lock held */
-static void pfg_del_from_list(struct pf_group *pfg)
-{
- list_del(&pfg->list);
-}
-
-
-static void msg_info(struct sspt_filter *f, void *data)
-{
- if (f->pfg_is_inst == false) {
- struct pfg_msg_cb *cb;
-
- f->pfg_is_inst = true;
-
- cb = pfg_msg_cb_get(f->pfg);
- if (cb) {
- struct dentry *dentry;
-
- dentry = (struct dentry *)f->pfg->filter.priv;
-
- if (cb->msg_info)
- cb->msg_info(f->proc->task, dentry);
-
- if (cb->msg_status_info)
- cb->msg_status_info(f->proc->task);
- }
- }
-}
-
-static void first_install(struct task_struct *task, struct sspt_proc *proc)
-{
- sspt_proc_priv_create(proc);
-
- down_write(&task->mm->mmap_sem);
- sspt_proc_on_each_filter(proc, msg_info, NULL);
- sspt_proc_install(proc);
- up_write(&task->mm->mmap_sem);
-}
-
-static void subsequent_install(struct task_struct *task,
- struct sspt_proc *proc, unsigned long page_addr)
-{
- down_write(&task->mm->mmap_sem);
- sspt_proc_install_page(proc, page_addr);
- up_write(&task->mm->mmap_sem);
-}
-
-/**
- * @brief Get dentry struct by path
- *
- * @param path Path to file
- * @return Pointer on dentry struct on NULL
- */
-struct dentry *dentry_by_path(const char *path)
-{
- struct dentry *dentry;
- struct path st_path;
- if (kern_path(path, LOOKUP_FOLLOW, &st_path) != 0) {
- printk("failed to lookup dentry for path %s!\n", path);
- return NULL;
- }
-
- dentry = st_path.dentry;
- path_put(&st_path);
- return dentry;
-}
-EXPORT_SYMBOL_GPL(dentry_by_path);
-
-
-int pfg_msg_cb_set(struct pf_group *pfg, struct pfg_msg_cb *msg_cb)
-{
- if (pfg->msg_cb)
- return -EBUSY;
-
- pfg->msg_cb = msg_cb;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pfg_msg_cb_set);
-
-void pfg_msg_cb_reset(struct pf_group *pfg)
-{
- pfg->msg_cb = NULL;
-}
-EXPORT_SYMBOL_GPL(pfg_msg_cb_reset);
-
-struct pfg_msg_cb *pfg_msg_cb_get(struct pf_group *pfg)
-{
- return pfg->msg_cb;
-}
-
-/**
- * @brief Get pf_group struct by dentry
- *
- * @param dentry Dentry of file
- * @param priv Private data
- * @return Pointer on pf_group struct
- */
-struct pf_group *get_pf_group_by_dentry(struct dentry *dentry, void *priv)
-{
- struct pf_group *pfg;
-
- write_lock(&pfg_list_lock);
- list_for_each_entry(pfg, &pfg_list, list) {
- if (check_pf_by_dentry(&pfg->filter, dentry)) {
- atomic_inc(&pfg->usage);
- goto unlock;
- }
- }
-
- pfg = pfg_create();
- if (pfg == NULL)
- goto unlock;
-
- set_pf_by_dentry(&pfg->filter, dentry, priv);
-
- pfg_add_to_list(pfg);
-
-unlock:
- write_unlock(&pfg_list_lock);
- return pfg;
-}
-EXPORT_SYMBOL_GPL(get_pf_group_by_dentry);
-
-/**
- * @brief Get pf_group struct by TGID
- *
- * @param tgid Thread group ID
- * @param priv Private data
- * @return Pointer on pf_group struct
- */
-struct pf_group *get_pf_group_by_tgid(pid_t tgid, void *priv)
-{
- struct pf_group *pfg;
-
- write_lock(&pfg_list_lock);
- list_for_each_entry(pfg, &pfg_list, list) {
- if (check_pf_by_tgid(&pfg->filter, tgid)) {
- atomic_inc(&pfg->usage);
- goto unlock;
- }
- }
-
- pfg = pfg_create();
- if (pfg == NULL)
- goto unlock;
-
- set_pf_by_tgid(&pfg->filter, tgid, priv);
-
- pfg_add_to_list(pfg);
-
-unlock:
- write_unlock(&pfg_list_lock);
- return pfg;
-}
-EXPORT_SYMBOL_GPL(get_pf_group_by_tgid);
-
-/**
- * @brief Get pf_group struct by comm
- *
- * @param comm Task comm
- * @param priv Private data
- * @return Pointer on pf_group struct
- */
-struct pf_group *get_pf_group_by_comm(char *comm, void *priv)
-{
- int ret;
- struct pf_group *pfg;
-
- write_lock(&pfg_list_lock);
- list_for_each_entry(pfg, &pfg_list, list) {
- if (check_pf_by_comm(&pfg->filter, comm)) {
- atomic_inc(&pfg->usage);
- goto unlock;
- }
- }
-
- pfg = pfg_create();
- if (pfg == NULL)
- goto unlock;
-
- ret = set_pf_by_comm(&pfg->filter, comm, priv);
- if (ret) {
- printk(KERN_ERR "ERROR: set_pf_by_comm, ret=%d\n", ret);
- pfg_free(pfg);
- pfg = NULL;
- goto unlock;
- }
-
- pfg_add_to_list(pfg);
-unlock:
- write_unlock(&pfg_list_lock);
- return pfg;
-}
-EXPORT_SYMBOL_GPL(get_pf_group_by_comm);
-
-/**
- * @brief Get pf_group struct for each process
- *
- * @param priv Private data
- * @return Pointer on pf_group struct
- */
-struct pf_group *get_pf_group_dumb(void *priv)
-{
- struct pf_group *pfg;
-
- write_lock(&pfg_list_lock);
- list_for_each_entry(pfg, &pfg_list, list) {
- if (check_pf_dumb(&pfg->filter)) {
- atomic_inc(&pfg->usage);
- goto unlock;
- }
- }
-
- pfg = pfg_create();
- if (pfg == NULL)
- goto unlock;
-
- set_pf_dumb(&pfg->filter, priv);
-
- pfg_add_to_list(pfg);
-
-unlock:
- write_unlock(&pfg_list_lock);
- return pfg;
-}
-EXPORT_SYMBOL_GPL(get_pf_group_dumb);
-
-/**
- * @brief Put pf_group struct
- *
- * @param pfg Pointer to the pf_group struct
- * @return Void
- */
-void put_pf_group(struct pf_group *pfg)
-{
- if (atomic_dec_and_test(&pfg->usage)) {
- write_lock(&pfg_list_lock);
- pfg_del_from_list(pfg);
- write_unlock(&pfg_list_lock);
-
- pfg_free(pfg);
- }
-}
-EXPORT_SYMBOL_GPL(put_pf_group);
-
-/**
- * @brief Register prober for pf_grpup struct
- *
- * @param pfg Pointer to the pf_group struct
- * @param dentry Dentry of file
- * @param offset Function offset
- * @param probe_info Pointer to the related probe_info struct
- * @return Error code
- */
-int pf_register_probe(struct pf_group *pfg, struct dentry *dentry,
- unsigned long offset, struct probe_info *probe_i)
-{
- return img_proc_add_ip(pfg->i_proc, dentry, offset, probe_i);
-}
-EXPORT_SYMBOL_GPL(pf_register_probe);
-
-/**
- * @brief Unregister prober from pf_grpup struct
- *
- * @param pfg Pointer to the pf_group struct
- * @param dentry Dentry of file
- * @param offset Function offset
- * @return Error code
- */
-int pf_unregister_probe(struct pf_group *pfg, struct dentry *dentry,
- unsigned long offset)
-{
- return img_proc_del_ip(pfg->i_proc, dentry, offset);
-}
-EXPORT_SYMBOL_GPL(pf_unregister_probe);
-
-/**
- * @brief Check the task, to meet the filter criteria
- *
- * @prarm task Pointer on the task_struct struct
- * @return
- * - 0 - false
- * - 1 - true
- */
-int check_task_on_filters(struct task_struct *task)
-{
- int ret = 0;
- struct pf_group *pfg;
-
- read_lock(&pfg_list_lock);
- list_for_each_entry(pfg, &pfg_list, list) {
- if (check_task_f(&pfg->filter, task)) {
- ret = 1;
- goto unlock;
- }
- }
-
-unlock:
- read_unlock(&pfg_list_lock);
- return ret;
-}
-
-enum pf_inst_flag {
- PIF_NONE,
- PIF_FIRST,
- PIF_SECOND,
- PIF_ADD_PFG
-};
-
-static enum pf_inst_flag pfg_check_task(struct task_struct *task)
-{
- struct pf_group *pfg;
- struct sspt_proc *proc = NULL;
- enum pf_inst_flag flag = PIF_NONE;
-
- read_lock(&pfg_list_lock);
- list_for_each_entry(pfg, &pfg_list, list) {
- if (check_task_f(&pfg->filter, task) == NULL)
- continue;
-
- if (proc == NULL)
- proc = sspt_proc_get_by_task(task);
-
- if (proc) {
- flag = flag == PIF_NONE ? PIF_SECOND : flag;
- } else if (task->tgid == task->pid) {
- proc = sspt_proc_get_by_task_or_new(task);
- if (proc == NULL) {
- printk(KERN_ERR "cannot create sspt_proc\n");
- break;
- }
- flag = PIF_FIRST;
- }
-
- if (proc) {
- write_lock(&proc->filter_lock);
- if (sspt_proc_is_filter_new(proc, pfg)) {
- img_proc_copy_to_sspt(pfg->i_proc, proc);
- sspt_proc_add_filter(proc, pfg);
- pfg_add_proc(pfg, proc);
- flag = flag == PIF_FIRST ? flag : PIF_ADD_PFG;
- }
- write_unlock(&proc->filter_lock);
- }
- }
- read_unlock(&pfg_list_lock);
-
- return flag;
-}
-
-/**
- * @brief Check task and install probes on demand
- *
- * @prarm task Pointer on the task_struct struct
- * @return Void
- */
-void check_task_and_install(struct task_struct *task)
-{
- struct sspt_proc *proc;
- enum pf_inst_flag flag;
-
- flag = pfg_check_task(task);
- switch (flag) {
- case PIF_FIRST:
- case PIF_ADD_PFG:
- proc = sspt_proc_get_by_task(task);
- if (proc)
- first_install(task, proc);
- break;
-
- case PIF_NONE:
- case PIF_SECOND:
- break;
- }
-}
-
-/**
- * @brief Check task and install probes on demand
- *
- * @prarm task Pointer on the task_struct struct
- * @param page_addr Page fault address
- * @return Void
- */
-void call_page_fault(struct task_struct *task, unsigned long page_addr)
-{
- struct sspt_proc *proc;
- enum pf_inst_flag flag;
-
- flag = pfg_check_task(task);
- switch (flag) {
- case PIF_FIRST:
- case PIF_ADD_PFG:
- proc = sspt_proc_get_by_task(task);
- if (proc)
- first_install(task, proc);
- break;
-
- case PIF_SECOND:
- proc = sspt_proc_get_by_task(task);
- if (proc)
- subsequent_install(task, proc, page_addr);
- break;
-
- case PIF_NONE:
- break;
- }
-}
-
-/**
- * @brief Uninstall probes from the sspt_proc struct
- *
- * @prarm proc Pointer on the sspt_proc struct
- * @return Void
- */
-
-/* called with sspt_proc_write_lock() */
-void uninstall_proc(struct sspt_proc *proc)
-{
- struct task_struct *task = proc->task;
-
- sspt_proc_uninstall(proc, task, US_UNREGS_PROBE);
- sspt_proc_cleanup(proc);
-}
-
-/**
- * @brief Remove probes from the task on demand
- *
- * @prarm task Pointer on the task_struct struct
- * @return Void
- */
-void call_mm_release(struct task_struct *task)
-{
- struct sspt_proc *proc;
-
- sspt_proc_write_lock();
- proc = sspt_proc_get_by_task_no_lock(task);
- if (proc)
- list_del(&proc->list);
- sspt_proc_write_unlock();
-
- if (proc)
- uninstall_proc(proc);
-}
-
-/**
- * @brief Legacy code, it is need remove
- *
- * @param addr Page address
- * @return Void
- */
-void uninstall_page(unsigned long addr)
-{
-
-}
-
-/**
- * @brief Install probes on running processes
- *
- * @return Void
- */
-void install_all(void)
-{
- /* TODO: to be implemented */
-}
-
-/**
- * @brief Uninstall probes from all processes
- *
- * @return Void
- */
-void uninstall_all(void)
-{
- struct list_head *proc_list = sspt_proc_list();
-
- sspt_proc_write_lock();
- while (!list_empty(proc_list)) {
- struct sspt_proc *proc;
- proc = list_first_entry(proc_list, struct sspt_proc, list);
-
- list_del(&proc->list);
-
- sspt_proc_write_unlock();
- uninstall_proc(proc);
- sspt_proc_write_lock();
- }
- sspt_proc_write_unlock();
-}
-
-static void __do_get_proc(struct sspt_proc *proc, void *data)
-{
- get_task_struct(proc->task);
- proc->__task = proc->task;
- proc->__mm = get_task_mm(proc->task);
-}
-
-static void __do_put_proc(struct sspt_proc *proc, void *data)
-{
- if (proc->__mm) {
- mmput(proc->__mm);
- proc->__mm = NULL;
- }
-
- if (proc->__task) {
- put_task_struct(proc->__task);
- proc->__task = NULL;
- }
-}
-
-void get_all_procs(void)
-{
- sspt_proc_read_lock();
- on_each_proc_no_lock(__do_get_proc, NULL);
- sspt_proc_read_unlock();
-}
-
-void put_all_procs(void)
-{
- sspt_proc_read_lock();
- on_each_proc_no_lock(__do_put_proc, NULL);
- sspt_proc_read_unlock();
-}
-
-/**
- * @brief For debug
- *
- * @param pfg Pointer to the pf_group struct
- * @return Void
- */
-
-/* debug */
-void pfg_print(struct pf_group *pfg)
-{
- img_proc_print(pfg->i_proc);
-}
-EXPORT_SYMBOL_GPL(pfg_print);
-/* debug */
+++ /dev/null
-/**
- * @file us_manager/pf/pf_group.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-
-#ifndef _PF_GROUP_H
-#define _PF_GROUP_H
-
-#include <linux/types.h>
-
-struct dentry;
-struct pf_group;
-struct sspt_proc;
-struct probe_info;
-
-
-struct pfg_msg_cb {
- void (*msg_info)(struct task_struct *task, struct dentry *dentry);
- void (*msg_status_info)(struct task_struct *task);
- void (*msg_term)(struct task_struct *task);
- void (*msg_map)(struct vm_area_struct *vma);
- void (*msg_unmap)(unsigned long start, unsigned long end);
-};
-
-
-/* FIXME: create and use get_dentry() and put_dentry() */
-struct dentry *dentry_by_path(const char *path);
-
-struct pf_group *get_pf_group_by_dentry(struct dentry *dentry, void *priv);
-struct pf_group *get_pf_group_by_tgid(pid_t tgid, void *priv);
-struct pf_group *get_pf_group_by_comm(char *comm, void *priv);
-struct pf_group *get_pf_group_dumb(void *priv);
-void put_pf_group(struct pf_group *pfg);
-
-int pfg_msg_cb_set(struct pf_group *pfg, struct pfg_msg_cb *msg_cb);
-void pfg_msg_cb_reset(struct pf_group *pfg);
-struct pfg_msg_cb *pfg_msg_cb_get(struct pf_group *pfg);
-
-int pf_register_probe(struct pf_group *pfg, struct dentry *dentry,
- unsigned long offset, struct probe_info *probe_i);
-int pf_unregister_probe(struct pf_group *pfg, struct dentry *dentry,
- unsigned long offset);
-
-void install_all(void);
-void uninstall_all(void);
-
-void get_all_procs(void);
-void put_all_procs(void);
-
-int check_task_on_filters(struct task_struct *task);
-void call_page_fault(struct task_struct *task, unsigned long page_addr);
-void call_mm_release(struct task_struct *task);
-void check_task_and_install(struct task_struct *task);
-void uninstall_proc(struct sspt_proc *proc);
-
-void uninstall_page(unsigned long addr);
-
-/* debug */
-void pfg_print(struct pf_group *pfg);
-/* debug */
-
-#endif /* _PF_GROUP_H */
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/pf/proc_filters.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/mm_types.h>
-#include <linux/string.h>
-#include <linux/fs.h>
-#include "proc_filters.h"
-#include <us_manager/sspt/sspt.h>
-
-static int check_dentry(struct task_struct *task, struct dentry *dentry)
-{
- struct vm_area_struct *vma;
- struct mm_struct *mm = task->mm;
-
- if (mm == NULL)
- return 0;
-
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- if (check_vma(vma) && vma->vm_file->f_dentry == dentry)
- return 1;
- }
-
- return 0;
-}
-
-static struct task_struct *call_by_dentry(struct proc_filter *self,
- struct task_struct *task)
-{
- struct dentry *dentry = (struct dentry *)self->data;
-
- if (!dentry || check_dentry(task, dentry))
- return task;
-
- return NULL;
-}
-
-static inline void free_by_dentry(struct proc_filter *self)
-{
- return;
-}
-
-static struct task_struct *call_by_tgid(struct proc_filter *self,
- struct task_struct *task)
-{
- pid_t tgid = (pid_t)self->data;
-
- if (task->tgid == tgid)
- return task;
-
- return NULL;
-}
-
-static inline void free_by_tgid(struct proc_filter *self)
-{
- return;
-}
-
-static struct task_struct *call_by_comm(struct proc_filter *self,
- struct task_struct *task)
-{
- struct task_struct *parent;
- char *comm = (char *)self->data;
- size_t len = strnlen(comm, TASK_COMM_LEN);
-
- if (!strncmp(comm, task->comm, len))
- return task;
-
- parent = task->parent;
- if (parent && !strncmp(comm, parent->comm, len))
- return task;
-
- return NULL;
-}
-
-static inline void free_by_comm(struct proc_filter *self)
-{
- kfree(self->data);
-}
-
-/* Dumb call. Each task is exactly what we are looking for :) */
-static struct task_struct *call_dumb(struct proc_filter *self,
- struct task_struct *task)
-{
- return task;
-}
-
-/**
- * @brief Filling pf_group struct by dentry
- *
- * @param pf Pointer to the proc_filter struct
- * @param dentry Dentry
- * @param priv Private data
- * @return Void
- */
-void set_pf_by_dentry(struct proc_filter *pf, struct dentry *dentry, void *priv)
-{
- pf->call = &call_by_dentry;
- pf->data = (void *)dentry;
- pf->priv = priv;
-}
-
-/**
- * @brief Filling pf_group struct by TGID
- *
- * @param pf Pointer to the proc_filter struct
- * @param tgid Thread group ID
- * @param priv Private data
- * @return Void
- */
-void set_pf_by_tgid(struct proc_filter *pf, pid_t tgid, void *priv)
-{
- pf->call = &call_by_tgid;
- pf->data = (void *)tgid;
- pf->priv = priv;
-}
-
-/**
- * @brief Fill proc_filter struct for given comm
- *
- * @param pf Pointer to the proc_filter struct
- * @param comm Task comm
- * @param priv Private data
- * @return 0 on suceess, error code on error.
- */
-int set_pf_by_comm(struct proc_filter *pf, char *comm, void *priv)
-{
- size_t len = strnlen(comm, TASK_COMM_LEN);
- char *new_comm = kmalloc(len, GFP_KERNEL);
-
- if (new_comm == NULL)
- return -ENOMEM;
-
- /* copy comm */
- memcpy(new_comm, comm, len - 1);
- new_comm[len - 1] = '\0';
-
- pf->call = &call_by_comm;
- pf->data = new_comm;
- pf->priv = priv;
-
- return 0;
-}
-
-/**
- * @brief Filling pf_group struct for each process
- *
- * @param pf Pointer to the proc_filter struct
- * @param priv Private data
- * @return Void
- */
-void set_pf_dumb(struct proc_filter *pf, void *priv)
-{
- pf->call = &call_dumb;
- pf->data = NULL;
- pf->priv = priv;
-}
-
-/**
- * @brief Free proc_filter struct
- *
- * @param filter Pointer to the proc_filter struct
- * @return Void
- */
-void free_pf(struct proc_filter *filter)
-{
- if (filter->call == &call_by_dentry)
- free_by_dentry(filter);
- else if (filter->call == &call_by_tgid)
- free_by_tgid(filter);
- else if (filter->call == &call_by_comm)
- free_by_comm(filter);
-}
-
-/**
- * @brief Check pf_group struct by dentry
- *
- * @param filter Pointer to the proc_filter struct
- * @param dentry Dentry
- * @return
- * - 0 - false
- * - 1 - true
- */
-int check_pf_by_dentry(struct proc_filter *filter, struct dentry *dentry)
-{
- return filter->data == (void *)dentry &&
- filter->call == &call_by_dentry;
-}
-
-/**
- * @brief Check pf_group struct by TGID
- *
- * @param filter Pointer to the proc_filter struct
- * @param tgid Thread group ID
- * @return
- * - 0 - false
- * - 1 - true
- */
-int check_pf_by_tgid(struct proc_filter *filter, pid_t tgid)
-{
- return filter->data == (void *)tgid && filter->call == &call_by_tgid;
-}
-
-/**
- * @brief Check proc_filter struct by comm
- *
- * @param filter Pointer to the proc_filter struct
- * @param comm Task comm
- * @return
- * - 0 - false
- * - 1 - true
- */
-int check_pf_by_comm(struct proc_filter *filter, char *comm)
-{
- return ((filter->call == &call_by_comm) && (filter->data != NULL) &&
- (!strncmp(filter->data, comm, TASK_COMM_LEN - 1)));
-}
-
-/**
- * @brief Dumb check always true if filter is a dumb one
- *
- * @param filter Pointer to the proc_filter struct
- * @return
- * - 0 - false
- * - 1 - true
- */
-int check_pf_dumb(struct proc_filter *filter)
-{
- return filter->call == &call_dumb;
-}
-
-/**
- * @brief Get priv from pf_group struct
- *
- * @param filter Pointer to the proc_filter struct
- * @return Pointer to the priv
- */
-void *get_pf_priv(struct proc_filter *filter)
-{
- return filter->priv;
-}
-
-/* Check function for call_page_fault() and other frequently called
-filter-check functions. It is used to call event-oriented and long-term filters
-only on specified events, but not every time memory map is changed. When
-iteraiting over the filters list, call this function on each step passing here
-pointer on filter. If it returns 1 then the filter should not be called. */
-int ignore_pf(struct proc_filter *filter)
-{
- return filter->call == &call_by_comm;
-}
+++ /dev/null
-/**
- * @file us_manager/pf/proc_filters.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-
-#ifndef _PROC_FILTERS_H
-#define _PROC_FILTERS_H
-
-#include <linux/types.h>
-
-struct dentry;
-struct task_struct;
-
-/**
- * @struct proc_filter
- * @breaf Filter for process
- */
-struct proc_filter {
- /** Callback for filtering */
- struct task_struct *(*call)(struct proc_filter *self,
- struct task_struct *task);
- void *data; /**< Data of callback */
- void *priv; /**< Private data */
-};
-
-/**
- * @def check_task_f @hideinitializer
- * Call filter on the task
- *
- * @param filter Pointer to the proc_filter struct
- * @param task Pointer to the task_struct struct
- */
-#define check_task_f(filter, task) ((filter)->call(filter, task))
-
-void set_pf_by_dentry(struct proc_filter *pf, struct dentry *dentry,
- void *priv);
-void set_pf_by_tgid(struct proc_filter *pf, pid_t tgid, void *priv);
-int set_pf_by_comm(struct proc_filter *pf, char *comm, void *priv);
-void set_pf_dumb(struct proc_filter *pf, void *priv);
-
-
-int check_pf_by_dentry(struct proc_filter *filter, struct dentry *dentry);
-int check_pf_by_tgid(struct proc_filter *filter, pid_t tgid);
-int check_pf_by_comm(struct proc_filter *filter, char *comm);
-int check_pf_dumb(struct proc_filter *filter);
-void *get_pf_priv(struct proc_filter *filter);
-
-void free_pf(struct proc_filter *filter);
-
-int ignore_pf(struct proc_filter *filter);
-
-#endif /* _PROC_FILTERS_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <us_manager/sspt/ip.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/sspt/sspt_proc.h>
-#include "probes.h"
-#include "probe_info_new.h"
-#include "register_probes.h"
-
-
-/*
- * handlers
- */
-static int urp_entry_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct uretprobe *rp = ri->rp;
-
- if (rp) {
- struct us_ip *ip = container_of(rp, struct us_ip, retprobe);
- struct probe_info_new *info_new;
-
- info_new = probe_info_get_val(ip->info, struct probe_info_new *);
- if (info_new->u.rp.entry_handler)
- return info_new->u.rp.entry_handler(ri, regs);
-
- }
-
- return 0;
-}
-
-static int urp_ret_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct uretprobe *rp = ri->rp;
-
- if (rp) {
- struct us_ip *ip = container_of(rp, struct us_ip, retprobe);
- struct probe_info_new *info_new;
-
- info_new = probe_info_get_val(ip->info, struct probe_info_new *);
- if (info_new->u.rp.ret_handler)
- return info_new->u.rp.ret_handler(ri, regs);
- }
-
- return 0;
-}
-
-static int uprobe_handler(struct kprobe *p, struct pt_regs *regs)
-{
- struct uprobe *up = container_of(p, struct uprobe, kp);
- struct us_ip *ip = container_of(up, struct us_ip, uprobe);
- struct probe_info_new *info_new;
-
- info_new = probe_info_get_val(ip->info, struct probe_info_new *);
- if (info_new->u.p.handler)
- return info_new->u.p.handler(p, regs);
-
- return 0;
-}
-
-
-
-
-void pin_set_probe(struct probe_info_otg *otg, unsigned long vaddr)
-{
- struct sspt_proc *proc;
- struct task_struct *task = current;
-
- otg->info.probe_type = otg->data->type;
- otg->info.size = sizeof(struct probe_info_new *);
-
- proc = sspt_proc_get_by_task(task);
- if (proc) {
- sspt_proc_install_probe(proc, vaddr, &otg->info);
- } else {
- pr_err("task[%u %u %s] not in sspt\n",
- task->tgid, task->pid, task->comm);
- }
-}
-EXPORT_SYMBOL_GPL(pin_set_probe);
-
-/*
- * register/unregister interface
- */
-int pin_register(struct probe_new *probe, struct pf_group *pfg,
- struct dentry *dentry)
-{
- int ret;
- struct probe_info *info;
- struct probe_info_new *info_new = probe->info;
-
- info = probe_info_create(struct probe_info_new *, info_new->type);
- if (info == NULL)
- return -ENOMEM;
-
- probe_info_set_val(info, struct probe_info_new *, info_new);
-
- ret = pf_register_probe(pfg, dentry, probe->offset, info);
- if (ret) {
- probe_info_free(info);
- return ret;
- }
-
- info_new->info = info;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pin_register);
-
-int pin_unregister(struct probe_new *probe, struct pf_group *pfg,
- struct dentry *dentry)
-{
- int ret;
- struct probe_info_new *info_new = probe->info;
-
- ret = pf_unregister_probe(pfg, dentry, probe->offset);
- if (ret) {
- /* error */
- return ret;
- }
-
- probe_info_free(info_new->info);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pin_unregister);
-
-
-
-
-
-/*
- * SWAP_NEW_UP
- */
-static int up_copy(struct probe_info *dst, const struct probe_info *src)
-{
- return 0;
-}
-
-static void up_cleanup(struct probe_info *probe_i)
-{
-}
-
-static struct uprobe *up_get_uprobe(struct us_ip *ip)
-{
- return &ip->uprobe;
-}
-
-static int up_register_probe(struct us_ip *ip)
-{
- return swap_register_uprobe(&ip->uprobe);
-}
-
-static void up_unregister_probe(struct us_ip *ip, int disarm)
-{
- __swap_unregister_uprobe(&ip->uprobe, disarm);
-}
-
-static void up_init(struct us_ip *ip)
-{
- ip->uprobe.kp.pre_handler = uprobe_handler;
-}
-
-static void up_uninit(struct us_ip *ip)
-{
-}
-
-static struct probe_iface up_iface = {
- .init = up_init,
- .uninit = up_uninit,
- .reg = up_register_probe,
- .unreg = up_unregister_probe,
- .get_uprobe = up_get_uprobe,
- .copy = up_copy,
- .cleanup = up_cleanup
-};
-
-
-
-
-
-/*
- * SWAP_NEW_URP
- */
-static int urp_copy(struct probe_info *dst, const struct probe_info *src)
-{
- return 0;
-}
-
-static void urp_cleanup(struct probe_info *probe_i)
-{
-}
-
-static struct uprobe *urp_get_uprobe(struct us_ip *ip)
-{
- return &ip->retprobe.up;
-}
-
-static int urp_register_probe(struct us_ip *ip)
-{
- return swap_register_uretprobe(&ip->retprobe);
-}
-
-static void urp_unregister_probe(struct us_ip *ip, int disarm)
-{
- __swap_unregister_uretprobe(&ip->retprobe, disarm);
-}
-
-static void urp_init(struct us_ip *ip)
-{
- ip->retprobe.entry_handler = urp_entry_handler;
- ip->retprobe.handler = urp_ret_handler;
- ip->retprobe.maxactive = 0;
- /* FIXME: make dynamic size field 'data_size' */
- ip->retprobe.data_size = sizeof(void *);
-}
-
-static void urp_uninit(struct us_ip *ip)
-{
-}
-
-static struct probe_iface urp_iface = {
- .init = urp_init,
- .uninit = urp_uninit,
- .reg = urp_register_probe,
- .unreg = urp_unregister_probe,
- .get_uprobe = urp_get_uprobe,
- .copy = urp_copy,
- .cleanup = urp_cleanup
-};
-
-
-
-
-/*
- * init/exit()
- */
-int pin_init(void)
-{
- int ret;
-
- ret = swap_register_probe_type(SWAP_NEW_UP, &up_iface);
- if (ret)
- return ret;
-
- ret = swap_register_probe_type(SWAP_NEW_URP, &urp_iface);
- if (ret)
- swap_unregister_probe_type(SWAP_NEW_UP);
-
- return ret;
-}
-
-void pin_exit(void)
-{
- swap_unregister_probe_type(SWAP_NEW_URP);
- swap_unregister_probe_type(SWAP_NEW_UP);
-}
+++ /dev/null
-#ifndef _PROBE_INFO_NEW_H
-#define _PROBE_INFO_NEW_H
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <kprobe/swap_kprobes.h>
-#include <uprobe/swap_uprobes.h>
-#include "probes.h"
-
-
-struct dentry;
-struct pf_group;
-
-
-struct probe_info_new {
- enum probe_t type;
- union {
- struct {
- kprobe_pre_handler_t handler;
- } p;
-
- struct {
- uretprobe_handler_t entry_handler;
- uretprobe_handler_t ret_handler;
- /*
- * FIXME: make dynamic size,
- * currently data_size = sizeof(void *)
- */
- size_t data_size;
- } rp;
- } u;
-
- /* private */
- struct probe_info *info;
-};
-
-
-struct probe_new {
- unsigned long offset;
- struct probe_info_new *info;
-};
-
-
-#define MAKE_UPROBE(_handler) \
- { \
- .type = SWAP_NEW_UP, \
- .u.p.handler = _handler \
- }
-
-#define MAKE_URPROBE(_entry, _ret, _size) \
- { \
- .type = SWAP_NEW_URP, \
- .u.rp.entry_handler = _entry, \
- .u.rp.ret_handler = _ret, \
- .u.rp.data_size = _size \
- }
-
-struct probe_info_otg {
- struct probe_info info;
- struct probe_info_new *data; /* field 'data[0]' in probe_info struct */
-};
-
-void pin_set_probe(struct probe_info_otg *otg, unsigned long vaddr);
-
-int pin_register(struct probe_new *probe, struct pf_group *pfg,
- struct dentry *dentry);
-int pin_unregister(struct probe_new *probe, struct pf_group *pfg,
- struct dentry *dentry);
-
-
-int pin_init(void);
-void pin_exit(void);
-
-
-#endif /* _PROBE_INFO_NEW_H */
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/probes/probes.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Alexander Aksenov: Probes interface implement
- *
- */
-
-#include "probes.h"
-#include "register_probes.h"
-#include "use_probes.h"
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-
-
-struct probe_info *probe_info_malloc(size_t size, enum probe_t type)
-{
- struct probe_info *info;
-
- info = kmalloc(sizeof(*info) + size, GFP_ATOMIC);
- if (info) {
- info->probe_type = type;
- info->size = size;
- }
-
- return info;
-}
-EXPORT_SYMBOL_GPL(probe_info_malloc);
-
-struct probe_info *probe_info_dup(const struct probe_info *info)
-{
- struct probe_info *info_new;
- size_t size = info->size;
-
- info_new = probe_info_malloc(size, info->probe_type);
- if (info_new && size)
- memcpy(info_new->data, info->data, size);
-
- return info_new;
-}
-EXPORT_SYMBOL_GPL(probe_info_dup);
-
-void probe_info_free(struct probe_info *info)
-{
- kfree(info);
-}
-EXPORT_SYMBOL_GPL(probe_info_free);
-
-
-static struct probe_iface *probes_methods[SWAP_PROBE_MAX_VAL] = { NULL };
-
-/* 1 - correct probe type
- 0 - wrong probe type
-*/
-static inline int correct_probe_type(enum probe_t probe_type)
-{
- if (probe_type >= SWAP_PROBE_MAX_VAL)
- return 0;
-
- return 1;
-}
-
-static inline int methods_exist(enum probe_t probe_type)
-{
- if (!correct_probe_type(probe_type))
- return 0;
-
- if (probes_methods[probe_type] == NULL)
- return 0;
-
- return 1;
-}
-
-/**
- * @brief Calls specified probe type init method.
- *
- * @param pi Pointer to the probe_info.
- * @param ip Pointer to the probe us_ip struct.
- * @return Void.
- */
-void probe_info_init(struct probe_info *pi, struct us_ip *ip)
-{
- enum probe_t probe_type = pi->probe_type;
-
- if (!methods_exist(probe_type)) {
- printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
- return;
- }
-
- probes_methods[probe_type]->init(ip);
-}
-
-/**
- * @brief Calls specified probe type uninit method.
- *
- * @param pi Pointer to the probe_info.
- * @param ip Pointer to the probe us_ip struct.
- * @return Void.
- */
-void probe_info_uninit(struct probe_info *pi, struct us_ip *ip)
-{
- enum probe_t probe_type = pi->probe_type;
-
- if (!methods_exist(probe_type)) {
- printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
- return;
- }
-
- probes_methods[probe_type]->uninit(ip);
-}
-
-/**
- * @brief Calls specified probe type register method.
- *
- * @param pi Pointer to the probe_info.
- * @param ip Pointer to the probe us_ip struct.
- * @return -EINVAL on wrong probe type, method result otherwise.
- */
-int probe_info_register(struct probe_info *pi, struct us_ip *ip)
-{
- enum probe_t probe_type = pi->probe_type;
-
- if (!methods_exist(probe_type)) {
- printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
- return -EINVAL;
- }
-
- return probes_methods[probe_type]->reg(ip);
-}
-
-/**
- * @brief Calls specified probe type unregister method.
- *
- * @param pi Pointer to the probe_info.
- * @param ip Pointer to the probe us_ip struct.
- * @param disarm Disarm flag.
- * @return Void.
- */
-void probe_info_unregister(struct probe_info *pi, struct us_ip *ip, int disarm)
-{
- enum probe_t probe_type = pi->probe_type;
-
- if (!methods_exist(probe_type)) {
- printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
- return;
- }
-
- probes_methods[probe_type]->unreg(ip, disarm);
-}
-
-/**
- * @brief Calls specified probe type get underlying uprobe method.
- *
- * @param pi Pointer to the probe_info.
- * @param ip Pointer to the probe us_ip struct.
- * @return Pointer to the uprobe struct, NULL on error.
- */
-struct uprobe *probe_info_get_uprobe(struct probe_info *pi, struct us_ip *ip)
-{
- enum probe_t probe_type = pi->probe_type;
-
- if (!methods_exist(probe_type)) {
- printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
- return NULL;
- }
-
- return probes_methods[probe_type]->get_uprobe(ip);
-}
-
-/**
- * @brief Calls specified probe type copy method.
- *
- * @param pi Pointer to the source probe_info.
- * @param dest Pointer to the probe us_ip struct.
- * @return -EINVAL on error, method result otherwise.
- */
-int probe_info_copy(const struct probe_info *pi, struct probe_info *dest)
-{
- enum probe_t probe_type = pi->probe_type;
-
- if (!methods_exist(probe_type)) {
- printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
- return -EINVAL;
- }
-
- return probes_methods[probe_type]->copy(dest, pi);
-}
-
-/**
- * @brief Calls specified probe type cleanup method.
- *
- * @param pi Pointer to the source probe_info.
- * @return Void.
- */
-void probe_info_cleanup(struct probe_info *pi)
-{
- enum probe_t probe_type = pi->probe_type;
-
- if (!methods_exist(probe_type)) {
- printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
- return;
- }
-
- probes_methods[probe_type]->cleanup(pi);
-}
-
-/**
- * @brief Registers probe type.
- *
- * @param probe_type Number, associated with this probe type.
- * @param pi Pointer to the probe interface structure
- * @return 0 on succes, error code on error.
- */
-int swap_register_probe_type(enum probe_t probe_type, struct probe_iface *pi)
-{
- if (!correct_probe_type(probe_type)) {
- printk(KERN_ERR "SWAP US_MANAGER: Wrong probe type!\n");
- return -EINVAL;
- }
-
- if (probes_methods[probe_type] != NULL)
- printk(KERN_WARNING "SWAP US_MANAGER: Re-registering probe %d\n",
- probe_type);
-
- probes_methods[probe_type] = pi;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(swap_register_probe_type);
-
-/**
- * @brief Unregisters probe type.
- *
- * @param probe_type Probe type that should be unregistered.
- * @return Void.
- */
-void swap_unregister_probe_type(enum probe_t probe_type)
-{
- if (!correct_probe_type(probe_type)) {
- printk(KERN_ERR "SWAP US_MANAGER: Wrong probe type!\n");
- return;
- }
-
- probes_methods[probe_type] = NULL;
-}
-EXPORT_SYMBOL_GPL(swap_unregister_probe_type);
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/probes/probes.h
- *
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2014 Alexander Aksenov : Probes interface implement
- * 2014 Vitaliy Cherepanov: Portage
- *
- */
-
-
-#ifndef __PROBES_H__
-#define __PROBES_H__
-
-#include <linux/types.h>
-
-#include <preload/preload_probe.h> /* TODO Remove */
-#include <retprobe/retprobe.h> /* TODO Remove */
-#include <fbiprobe/fbiprobe.h> /* TODO Remove */
-
-
-
-/* All probe types. Only us_manager should know about them - it is its own
- * business to install proper probes on proper places.
- */
-enum probe_t {
- SWAP_RETPROBE = 0, /* Retprobe */
- SWAP_FBIPROBE = 1, /* FBI probe */
- SWAP_PRELOAD_PROBE = 2, /* Preload probe */
- SWAP_WEBPROBE = 3, /* Webprobe */
- SWAP_GET_CALLER = 4, /* Get caller probe. Supports preload */
- SWAP_GET_CALL_TYPE = 5, /* Get call type probe. Supports preload */
- SWAP_WRITE_MSG = 6, /* Write messages from user space directly to
- * kernel. Supports preload */
- SWAP_NEW_UP,
- SWAP_NEW_URP,
- SWAP_PROBE_MAX_VAL /* Probes max value. */
-};
-
-/* Probe info stuct. It contains the whole information about probe. */
-struct probe_info {
- enum probe_t probe_type;
- size_t size;
- /* Union of all SWAP supported probe types */
- union {
- struct retprobe_info rp_i;
- struct fbi_info fbi_i;
- struct preload_info pl_i;
- struct get_caller_info gc_i;
- struct get_call_type_info gct_i;
- struct write_msg_info wm_i;
- };
-
- char data[0];
-};
-
-
-#define probe_info_create(val_t, type) probe_info_malloc(sizeof(val_t), type)
-struct probe_info *probe_info_malloc(size_t size, enum probe_t type);
-struct probe_info *probe_info_dup(const struct probe_info *info);
-void probe_info_free(struct probe_info *info);
-
-
-#define probe_info_get_data(info) ((void *)(info->data))
-#define probe_info_get_ptr(info, val_t) (val_t *)probe_info_get_data(info)
-#define probe_info_get_val(info, val_t) *probe_info_get_ptr(info, val_t)
-#define probe_info_set_val(info, val_t, v) *probe_info_get_ptr(info, val_t) = v
-
-
-#endif /* __PROBES_H__ */
+++ /dev/null
-#ifndef __REGISTER_PROBES_H__
-#define __REGISTER_PROBES_H__
-
-#include "probes.h"
-
-struct us_ip;
-
-struct probe_iface {
- void (*init)(struct us_ip *);
- void (*uninit)(struct us_ip *);
- int (*reg)(struct us_ip *);
- void (*unreg)(struct us_ip *, int);
- struct uprobe *(*get_uprobe)(struct us_ip *);
- int (*copy)(struct probe_info *, const struct probe_info *);
- void (*cleanup)(struct probe_info *);
-};
-
-int swap_register_probe_type(enum probe_t probe_type, struct probe_iface *pi);
-void swap_unregister_probe_type(enum probe_t probe_type);
-
-#endif /* __REGISTER_PROBES_H__ */
+++ /dev/null
-#ifndef __USE_PROBES_H__
-#define __USE_PROBES_H__
-
-#include "probes.h"
-
-struct us_ip;
-
-void probe_info_init(struct probe_info *pi, struct us_ip *ip);
-void probe_info_uninit(struct probe_info *pi, struct us_ip *ip);
-int probe_info_register(struct probe_info *pi, struct us_ip *ip);
-void probe_info_unregister(struct probe_info *pi, struct us_ip *ip, int disarm);
-struct uprobe *probe_info_get_uprobe(struct probe_info *pi, struct us_ip *ip);
-int probe_info_copy(const struct probe_info *pi, struct probe_info *dest);
-void probe_info_cleanup(struct probe_info *pi);
-
-#endif /* __USE_PROBES_H__ */
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * modules/driver/sspt/ip.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include "ip.h"
-#include "sspt_page.h"
-#include "sspt_file.h"
-#include <us_manager/probes/use_probes.h>
-
-/**
- * @brief Create us_ip struct
- *
- * @param page User page
- * @param offset Function offset from the beginning of the page
- * @param probe_i Pointer to the probe data.
- * @param page Pointer to the parent sspt_page struct
- * @return Pointer to the created us_ip struct
- */
-struct us_ip *create_ip(unsigned long offset, const struct probe_info *info,
- struct sspt_page *page)
-{
- struct us_ip *ip;
- struct probe_info *info_new;
-
- info_new = probe_info_dup(info);
- if (info_new == NULL) {
- printk("Cannot probe_info_dup in %s function!\n", __func__);
- return NULL;
- }
-
- ip = kmalloc(sizeof(*ip), GFP_ATOMIC);
- if (ip != NULL) {
- memset(ip, 0, sizeof(*ip));
-
- INIT_LIST_HEAD(&ip->list);
- ip->offset = offset;
- ip->page = page;
-
- probe_info_copy(info, info_new);
- probe_info_init(info_new, ip);
- ip->info = info_new;
- } else {
- printk(KERN_INFO "Cannot kmalloc in create_ip function!\n");
- probe_info_free(info_new);
- }
-
- return ip;
-}
-
-/**
- * @brief Remove us_ip struct
- *
- * @param ip remove object
- * @return Void
- */
-void free_ip(struct us_ip *ip)
-{
- probe_info_uninit(ip->info, ip);
- probe_info_free(ip->info);
- kfree(ip);
-}
+++ /dev/null
-#ifndef __IP__
-#define __IP__
-
-/**
- * @file us_manager/sspt/ip.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-#include <linux/list.h>
-#include <uprobe/swap_uprobes.h>
-#include <us_manager/probes/probes.h>
-
-struct sspt_page;
-
-/**
- * @struct us_ip
- * @breaf Image of instrumentation pointer for specified process
- */
-struct us_ip {
- struct list_head list; /**< For sspt_page */
- struct sspt_page *page; /**< Pointer on the page (parent) */
- struct probe_info *info; /**< Probe's data */
-
- unsigned long orig_addr; /**< Function address */
- unsigned long offset; /**< Page offset */
-
- union {
- struct uretprobe retprobe;
- struct uprobe uprobe;
- };
-};
-
-#define to_us_ip(rp) container_of(rp, struct us_ip, retprobe)
-
-struct us_ip *create_ip(unsigned long offset, const struct probe_info *info,
- struct sspt_page *page);
-void free_ip(struct us_ip *ip);
-
-#endif /* __IP__ */
+++ /dev/null
-#ifndef __SSPT__
-#define __SSPT__
-
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * modules/driver/sspt/sspt.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include "ip.h"
-#include "sspt_page.h"
-#include "sspt_file.h"
-#include "sspt_proc.h"
-#include "sspt_debug.h"
-#include <uprobe/swap_uprobes.h>
-
-
-#include <us_manager/us_manager.h>
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/probes/use_probes.h>
-
-
-static inline int check_vma(struct vm_area_struct *vma)
-{
- return vma->vm_file &&
- !(vma->vm_pgoff != 0 ||
- !(vma->vm_flags & VM_EXEC) ||
- !(vma->vm_flags & (VM_READ | VM_MAYREAD)));
-}
-
-static inline int sspt_register_usprobe(struct us_ip *ip)
-{
- int ret;
- struct uprobe *up = NULL;
-
- up = probe_info_get_uprobe(ip->info, ip);
-
- if (!up) {
- printk(KERN_INFO "SWAP US_MANAGER: failed getting uprobe!\n");
- return -EINVAL;
- }
-
- up->kp.addr = (kprobe_opcode_t *)ip->orig_addr;
- up->task = ip->page->file->proc->task;
- up->sm = ip->page->file->proc->sm;
- up->atomic_ctx = true;
-
- ret = probe_info_register(ip->info, ip);
- if (ret) {
- struct sspt_file *file = ip->page->file;
- char *name = file->dentry->d_iname;
- unsigned long addr = (unsigned long)up->kp.addr;
- unsigned long offset = addr - file->vm_start;
-
- printk(KERN_INFO "swap_register_uretprobe() failure %d "
- "(%s:%lx|%lx)\n", ret, name, offset,
- (unsigned long)ip->retprobe.up.kp.opcode);
- }
-
- return ret;
-}
-
-static inline int sspt_unregister_usprobe(struct task_struct *task,
- struct us_ip *ip,
- enum US_FLAGS flag)
-{
- struct uprobe *up = NULL;
-
- switch (flag) {
- case US_UNREGS_PROBE:
- probe_info_unregister(ip->info, ip, 1);
- break;
- case US_DISARM:
- up = probe_info_get_uprobe(ip->info, ip);
- if (up)
- disarm_uprobe(&up->kp, task);
- break;
- case US_UNINSTALL:
- probe_info_unregister(ip->info, ip, 0);
- break;
- default:
- panic("incorrect value flag=%d", flag);
- }
-
- return 0;
-}
-
-#endif /* __SSPT__ */
+++ /dev/null
-#ifndef __SSPT_DEBUG__
-#define __SSPT_DEBUG__
-
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * modules/driver/sspt/sspt_debug.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include <kprobe/swap_kprobes_deps.h>
-#include <us_manager/probes/probes.h>
-
-static inline void print_jprobe(struct jprobe *jp)
-{
- printk(KERN_INFO "### JP: entry=%lx, pre_entry=%lx\n",
- (unsigned long)jp->entry, (unsigned long)jp->pre_entry);
-}
-
-static inline void print_retprobe(struct uretprobe *rp)
-{
- printk(KERN_INFO "### RP: handler=%lx\n",
- (unsigned long)rp->handler);
-}
-
-static inline void print_ip(struct us_ip *ip, int i)
-{
- if (ip->info->probe_type == SWAP_RETPROBE) {
- struct uretprobe *rp = &ip->retprobe;
-
- printk(KERN_INFO "### addr[%2d]=%lx, R_addr=%lx\n",
- i, (unsigned long)ip->offset,
- (unsigned long)rp->up.kp.addr);
- print_retprobe(rp);
- }
-}
-
-static inline void print_page_probes(const struct sspt_page *page)
-{
- int i = 0;
- struct us_ip *ip;
-
- printk(KERN_INFO "### offset=%lx\n", page->offset);
- printk(KERN_INFO "### no install:\n");
- list_for_each_entry(ip, &page->ip_list_no_inst, list) {
- print_ip(ip, i);
- ++i;
- }
-
- printk(KERN_INFO "### install:\n");
- list_for_each_entry(ip, &page->ip_list_inst, list) {
- print_ip(ip, i);
- ++i;
- }
-}
-
-static inline void print_file_probes(const struct sspt_file *file)
-{
- int i;
- unsigned long table_size;
- struct sspt_page *page = NULL;
- struct hlist_head *head = NULL;
- static unsigned char *NA = "N/A";
- unsigned char *name;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- if (file == NULL) {
- printk(KERN_INFO "### file_p == NULL\n");
- return;
- }
-
- table_size = (1 << file->page_probes_hash_bits);
- name = (file->dentry) ? file->dentry->d_iname : NA;
-
- printk(KERN_INFO "### print_file_probes: path=%s, d_iname=%s, "
- "table_size=%lu, vm_start=%lx\n",
- file->dentry->d_iname, name, table_size, file->vm_start);
-
- for (i = 0; i < table_size; ++i) {
- head = &file->page_probes_table[i];
- swap_hlist_for_each_entry_rcu(page, node, head, hlist) {
- print_page_probes(page);
- }
- }
-}
-
-static inline void print_proc_probes(const struct sspt_proc *proc)
-{
- struct sspt_file *file;
-
- printk(KERN_INFO "### print_proc_probes\n");
- list_for_each_entry(file, &proc->file_list, list) {
- print_file_probes(file);
- }
- printk(KERN_INFO "### print_proc_probes\n");
-}
-
-/*
-static inline void print_inst_us_proc(const inst_us_proc_t *task_inst_info)
-{
- int i;
- int cnt = task_inst_info->libs_count;
- printk( "### BUNDLE PRINT START ###\n");
- printk(KERN_INFO "\n### BUNDLE PRINT START ###\n");
- printk(KERN_INFO "### task_inst_info.libs_count=%d\n", cnt);
-
- for (i = 0; i < cnt; ++i) {
- int j;
-
- us_proc_lib_t *lib = &task_inst_info->p_libs[i];
- int cnt_j = lib->ips_count;
- char *path = lib->path;
- printk(KERN_INFO "### path=%s, cnt_j=%d\n", path, cnt_j);
-
- for (j = 0; j < cnt_j; ++j) {
- us_proc_ip_t *ips = &lib->p_ips[j];
- unsigned long offset = ips->offset;
- printk(KERN_INFO "### offset=%lx\n", offset);
- }
- }
- printk(KERN_INFO "### BUNDLE PRINT END ###\n");
-}
-*/
-
-#endif /* __SSPT_DEBUG__ */
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * modules/us_manager/sspt/sspt_feature.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include "sspt_feature.h"
-#include "sspt_proc.h"
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-
-
-struct sspt_feature {
- struct list_head feature_list;
-};
-
-struct sspt_feature_img {
- struct list_head list;
-
- void *(*alloc)(void);
- void (*free)(void *data);
-};
-
-struct sspt_feature_data {
- struct list_head list;
-
- struct sspt_feature_img *img;
- void *data;
-};
-
-static DEFINE_SPINLOCK(feature_img_lock);
-static LIST_HEAD(feature_img_list);
-
-static struct sspt_feature_data *create_feature_data(
- struct sspt_feature_img *img)
-{
- struct sspt_feature_data *fd;
-
- fd = kmalloc(sizeof(*fd), GFP_ATOMIC);
- if (fd) {
- INIT_LIST_HEAD(&fd->list);
- fd->img = img;
- fd->data = img->alloc();
- }
-
- return fd;
-}
-
-static void destroy_feature_data(struct sspt_feature_data *fd)
-{
- fd->img->free(fd->data);
- kfree(fd);
-}
-
-/**
- * @brief Create sspt_feature struct
- *
- * @return Pointer to the created sspt_feature struct
- */
-struct sspt_feature *sspt_create_feature(void)
-{
- struct sspt_feature *f;
-
- f = kmalloc(sizeof(*f), GFP_ATOMIC);
- if (f) {
- struct sspt_feature_data *fd;
- struct sspt_feature_img *fi;
- unsigned long flags;
-
- INIT_LIST_HEAD(&f->feature_list);
-
- spin_lock_irqsave(&feature_img_lock, flags);
- list_for_each_entry(fi, &feature_img_list, list) {
- fd = create_feature_data(fi);
- if (fd) /* add to list */
- list_add(&fd->list, &f->feature_list);
- }
- spin_unlock_irqrestore(&feature_img_lock, flags);
- }
-
- return f;
-}
-
-/**
- * @brief Destroy sspt_feature struct
- *
- * @param f remove object
- * @return Void
- */
-void sspt_destroy_feature(struct sspt_feature *f)
-{
- struct sspt_feature_data *fd, *n;
-
- list_for_each_entry_safe(fd, n, &f->feature_list, list) {
- /* delete from list */
- list_del(&fd->list);
- destroy_feature_data(fd);
- }
-
- kfree(f);
-}
-
-static void add_feature_img_to_list(struct sspt_feature_img *fi)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&feature_img_lock, flags);
- list_add(&fi->list, &feature_img_list);
- spin_unlock_irqrestore(&feature_img_lock, flags);
-}
-
-static void del_feature_img_from_list(struct sspt_feature_img *fi)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&feature_img_lock, flags);
- list_del(&fi->list);
- spin_unlock_irqrestore(&feature_img_lock, flags);
-}
-
-static struct sspt_feature_img *create_feature_img(void *(*alloc)(void),
- void (*free)(void *data))
-{
- struct sspt_feature_img *fi;
-
- fi = kmalloc(sizeof(*fi), GFP_ATOMIC);
- if (fi) {
- INIT_LIST_HEAD(&fi->list);
- fi->alloc = alloc;
- fi->free = free;
-
- add_feature_img_to_list(fi);
- }
-
- return fi;
-}
-
-static void destroy_feature_img(struct sspt_feature_img *fi)
-{
- del_feature_img_from_list(fi);
-
- kfree(fi);
-}
-
-static void del_feature_by_img(struct sspt_feature *f,
- struct sspt_feature_img *img)
-{
- struct sspt_feature_data *fd;
-
- list_for_each_entry(fd, &f->feature_list, list) {
- if (img == fd->img) {
- /* delete from list */
- list_del(&fd->list);
- destroy_feature_data(fd);
- break;
- }
- }
-}
-
-static void del_feature_from_proc(struct sspt_proc *proc, void *data)
-{
- del_feature_by_img(proc->feature, (struct sspt_feature_img *)data);
-}
-
-/**
- * @brief Get data for feature
- *
- * @param f Pointer to the sspt_feature struct
- * @param id Feature ID
- * @return Pointer to the data
- */
-void *sspt_get_feature_data(struct sspt_feature *f, sspt_feature_id_t id)
-{
- struct sspt_feature_img *img = (struct sspt_feature_img *)id;
- struct sspt_feature_data *fd;
-
- list_for_each_entry(fd, &f->feature_list, list) {
- if (img == fd->img)
- return fd->data;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(sspt_get_feature_data);
-
-/**
- * @brief Register sspt feature
- *
- * @param alloc Callback for allocating data
- * @param free Callback to release data
- * @return Feature ID
- */
-sspt_feature_id_t sspt_register_feature(void *(*alloc)(void),
- void (*free)(void *data))
-{
- struct sspt_feature_img *fi;
-
- fi = create_feature_img(alloc, free);
-
- /* TODO: add to already instrumentation process */
-
- return (sspt_feature_id_t)fi;
-}
-EXPORT_SYMBOL_GPL(sspt_register_feature);
-
-/**
- * @brief Unregister sspt feature
- *
- * @param id Feature ID
- * @return Void
- */
-void sspt_unregister_feature(sspt_feature_id_t id)
-{
- struct sspt_feature_img *fi = (struct sspt_feature_img *)id;
-
- on_each_proc(del_feature_from_proc, (void *)fi);
- destroy_feature_img(fi);
-}
-EXPORT_SYMBOL_GPL(sspt_unregister_feature);
+++ /dev/null
-#ifndef _SSPT_FEATUER_H
-#define _SSPT_FEATUER_H
-
-/**
- * @file us_manager/sspt/sspt_feature.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-struct sspt_feature;
-
-typedef void *sspt_feature_id_t; /**< @brief sspt feature ID type */
-#define SSPT_FEATURE_ID_BAD NULL /**< @def SSPT_FEATURE_ID_BAD */
-
-struct sspt_feature *sspt_create_feature(void);
-void sspt_destroy_feature(struct sspt_feature *f);
-
-void *sspt_get_feature_data(struct sspt_feature *f, sspt_feature_id_t id);
-sspt_feature_id_t sspt_register_feature(void *(*alloc)(void),
- void (*free)(void *data));
-void sspt_unregister_feature(sspt_feature_id_t id);
-
-#endif /* _SSPT_FEATUER_H */
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * modules/driver/sspt/sspt_file.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include "sspt.h"
-#include "sspt_file.h"
-#include "sspt_page.h"
-#include "sspt_proc.h"
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/hash.h>
-#include <linux/sched.h>
-#include <kprobe/swap_kprobes_deps.h>
-
-static int calculation_hash_bits(int cnt)
-{
- int bits;
- for (bits = 1; cnt >>= 1; ++bits)
- ;
-
- return bits;
-}
-
-/**
- * @brief Create sspt_file struct
- *
- * @param dentry Dentry of file
- * @param page_cnt Size of hash-table
- * @return Pointer to the created sspt_file struct
- */
-struct sspt_file *sspt_file_create(struct dentry *dentry, int page_cnt)
-{
- int i, table_size;
- struct sspt_file *obj = kmalloc(sizeof(*obj), GFP_ATOMIC);
-
- if (obj == NULL)
- return NULL;
-
- INIT_LIST_HEAD(&obj->list);
- obj->proc = NULL;
- obj->dentry = dentry;
- obj->loaded = 0;
- obj->vm_start = 0;
- obj->vm_end = 0;
-
- obj->page_probes_hash_bits = calculation_hash_bits(page_cnt);
- table_size = (1 << obj->page_probes_hash_bits);
-
- obj->page_probes_table =
- kmalloc(sizeof(*obj->page_probes_table)*table_size,
- GFP_ATOMIC);
-
- if (obj->page_probes_table == NULL)
- goto err;
-
- for (i = 0; i < table_size; ++i)
- INIT_HLIST_HEAD(&obj->page_probes_table[i]);
-
- return obj;
-
-err:
- kfree(obj);
- return NULL;
-}
-
-/**
- * @brief Remove sspt_file struct
- *
- * @param file remove object
- * @return Void
- */
-void sspt_file_free(struct sspt_file *file)
-{
- struct hlist_head *head;
- struct sspt_page *page;
- int i, table_size = (1 << file->page_probes_hash_bits);
- struct hlist_node *n;
- DECLARE_NODE_PTR_FOR_HLIST(p);
-
- for (i = 0; i < table_size; ++i) {
- head = &file->page_probes_table[i];
- swap_hlist_for_each_entry_safe(page, p, n, head, hlist) {
- hlist_del(&page->hlist);
- sspt_page_free(page);
- }
- }
-
- kfree(file->page_probes_table);
- kfree(file);
-}
-
-static void sspt_add_page(struct sspt_file *file, struct sspt_page *page)
-{
- page->file = file;
- hlist_add_head(&page->hlist,
- &file->page_probes_table[hash_ptr(
- (void *)page->offset,
- file->page_probes_hash_bits)]);
-}
-
-static struct sspt_page *sspt_find_page(struct sspt_file *file,
- unsigned long offset)
-{
- struct hlist_head *head;
- struct sspt_page *page;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- head = &file->page_probes_table[hash_ptr((void *)offset,
- file->page_probes_hash_bits)];
- swap_hlist_for_each_entry(page, node, head, hlist) {
- if (page->offset == offset)
- return page;
- }
-
- return NULL;
-}
-
-static struct sspt_page *sspt_find_page_or_new(struct sspt_file *file,
- unsigned long offset)
-{
- struct sspt_page *page = sspt_find_page(file, offset);
-
- if (page == NULL) {
- page = sspt_page_create(offset);
- if (page)
- sspt_add_page(file, page);
- }
-
- return page;
-}
-
-/**
- * @brief Get sspt_page from sspt_file
- *
- * @param file Pointer to the sspt_file struct
- * @param page Page address
- * @return Pointer to the sspt_page struct
- */
-struct sspt_page *sspt_find_page_mapped(struct sspt_file *file,
- unsigned long page)
-{
- unsigned long offset;
-
- if (file->vm_start > page || file->vm_end < page) {
- /* TODO: or panic?! */
- printk(KERN_INFO "ERROR: file_p[vm_start..vm_end] <> page: "
- "file_p[vm_start=%lx, vm_end=%lx, "
- "d_iname=%s] page=%lx\n",
- file->vm_start, file->vm_end,
- file->dentry->d_iname, page);
- return NULL;
- }
-
- offset = page - file->vm_start;
-
- return sspt_find_page(file, offset);
-}
-
-/**
- * @brief Add instruction pointer to sspt_file
- *
- * @param file Pointer to the sspt_file struct
- * @param offset File offset
- * @param args Function arguments
- * @param ret_type Return type
- * @return Void
- */
-void sspt_file_add_ip(struct sspt_file *file, unsigned long offset,
- struct probe_info *probe_i)
-{
- struct sspt_page *page =
- sspt_find_page_or_new(file, offset & PAGE_MASK);
-
- /* FIXME: delete ip */
- struct us_ip *ip = create_ip(offset, probe_i, page);
-
- if (page && ip)
- sspt_add_ip(page, ip);
-}
-
-void sspt_file_on_each_ip(struct sspt_file *file,
- void (*func)(struct us_ip *, void *), void *data)
-{
- int i;
- const int table_size = (1 << file->page_probes_hash_bits);
- struct sspt_page *page;
- struct hlist_head *head;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- for (i = 0; i < table_size; ++i) {
- head = &file->page_probes_table[i];
- swap_hlist_for_each_entry(page, node, head, hlist)
- sspt_page_on_each_ip(page, func, data);
- }
-}
-
-/**
- * @brief Get sspt_page from sspt_file (look)
- *
- * @param file Pointer to the sspt_file struct
- * @param offset_addr File offset
- * @return Pointer to the sspt_page struct
- */
-struct sspt_page *sspt_get_page(struct sspt_file *file,
- unsigned long offset_addr)
-{
- unsigned long offset = offset_addr & PAGE_MASK;
- struct sspt_page *page = sspt_find_page_or_new(file, offset);
-
- spin_lock(&page->lock);
-
- return page;
-}
-
-/**
- * @brief Put sspt_page (unlook)
- *
- * @param file Pointer to the sspt_page struct
- * @return void
- */
-void sspt_put_page(struct sspt_page *page)
-{
- spin_unlock(&page->lock);
-}
-
-/**
- * @brief Check install sspt_file (legacy code, it is need remove)
- *
- * @param file Pointer to the sspt_file struct
- * @return
- * - 0 - false
- * - 1 - true
- */
-int sspt_file_check_install_pages(struct sspt_file *file)
-{
- int i, table_size;
- struct sspt_page *page;
- struct hlist_head *head;
- struct hlist_node *tmp;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- table_size = (1 << file->page_probes_hash_bits);
- for (i = 0; i < table_size; ++i) {
- head = &file->page_probes_table[i];
- swap_hlist_for_each_entry_safe(page, node, tmp, head, hlist) {
- if (sspt_page_is_installed(page))
- return 1;
- }
- }
-
- return 0;
-}
-
-/**
- * @brief Install sspt_file
- *
- * @param file Pointer to the sspt_file struct
- * @return Void
- */
-void sspt_file_install(struct sspt_file *file)
-{
- struct sspt_page *page = NULL;
- struct hlist_head *head = NULL;
- int i, table_size = (1 << file->page_probes_hash_bits);
- unsigned long page_addr;
- struct mm_struct *mm;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- for (i = 0; i < table_size; ++i) {
- head = &file->page_probes_table[i];
- swap_hlist_for_each_entry_rcu(page, node, head, hlist) {
- page_addr = file->vm_start + page->offset;
- if (page_addr < file->vm_start ||
- page_addr >= file->vm_end)
- continue;
-
- mm = page->file->proc->task->mm;
- if (page_present(mm, page_addr))
- sspt_register_page(page, file);
- }
- }
-}
-
-/**
- * @brief Uninstall sspt_file
- *
- * @param file Pointer to the sspt_file struct
- * @param task Pointer to the task_stract struct
- * @param flag Action for probes
- * @return Void
- */
-int sspt_file_uninstall(struct sspt_file *file,
- struct task_struct *task,
- enum US_FLAGS flag)
-{
- int i, err = 0;
- int table_size = (1 << file->page_probes_hash_bits);
- struct sspt_page *page;
- struct hlist_head *head;
- struct hlist_node *tmp;
- DECLARE_NODE_PTR_FOR_HLIST(node);
-
- for (i = 0; i < table_size; ++i) {
- head = &file->page_probes_table[i];
- swap_hlist_for_each_entry_safe(page, node, tmp, head, hlist) {
- err = sspt_unregister_page(page, flag, task);
- if (err != 0) {
- printk(KERN_INFO "ERROR sspt_file_uninstall: "
- "err=%d\n", err);
- return err;
- }
- }
- }
-
- if (flag != US_DISARM) {
- file->loaded = 0;
- file->vm_start = 0;
- file->vm_end = 0;
- }
-
- return err;
-}
-
-/**
- * @brief Set mapping for sspt_file
- *
- * @param file Pointer to the sspt_file struct
- * @param vma Pointer to the vm_area_struct struct
- * @return Void
- */
-void sspt_file_set_mapping(struct sspt_file *file, struct vm_area_struct *vma)
-{
- if (file->loaded == 0) {
- file->loaded = 1;
- file->vm_start = vma->vm_start;
- file->vm_end = vma->vm_end;
- }
-}
+++ /dev/null
-#ifndef __SSPT_FILE__
-#define __SSPT_FILE__
-
-/**
- * @file us_manager/sspt/sspt_file.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-#include "ip.h"
-#include <linux/types.h>
-
-enum US_FLAGS;
-struct vm_area_struct;
-
-/**
- * @struct sspt_file
- * @breaf Image of file for specified process
- */
-struct sspt_file {
- struct list_head list; /**< For sspt_proc */
- struct sspt_proc *proc; /**< Pointer to the proc (parent) */
- struct dentry *dentry; /**< Dentry of file */
- unsigned long vm_start; /**< VM start */
- unsigned long vm_end; /**< VM end */
-
- unsigned long page_probes_hash_bits; /**< Hash-table size */
- struct hlist_head *page_probes_table; /**< Hash-table for pages */
-
- unsigned loaded:1; /**< Flag of loading */
-};
-
-
-struct sspt_file *sspt_file_create(struct dentry *dentry, int page_cnt);
-void sspt_file_free(struct sspt_file *file);
-
-struct sspt_page *sspt_find_page_mapped(struct sspt_file *file,
- unsigned long page);
-void sspt_file_add_ip(struct sspt_file *file, unsigned long offset,
- struct probe_info *probe_i);
-
-void sspt_file_on_each_ip(struct sspt_file *file,
- void (*func)(struct us_ip *, void *), void *data);
-
-struct sspt_page *sspt_get_page(struct sspt_file *file,
- unsigned long offset_addr);
-void sspt_put_page(struct sspt_page *page);
-
-int sspt_file_check_install_pages(struct sspt_file *file);
-void sspt_file_install(struct sspt_file *file);
-int sspt_file_uninstall(struct sspt_file *file,
- struct task_struct *task,
- enum US_FLAGS flag);
-void sspt_file_set_mapping(struct sspt_file *file, struct vm_area_struct *vma);
-
-#endif /* __SSPT_FILE__ */
+++ /dev/null
-#include <linux/list.h>
-#include <linux/slab.h>
-#include "sspt_filter.h"
-#include "sspt_proc.h"
-#include "../pf/pf_group.h"
-
-
-struct sspt_filter *sspt_filter_create(struct sspt_proc *proc,
- struct pf_group *pfg)
-{
- struct sspt_filter *fl;
-
- fl = kmalloc(sizeof(*fl), GFP_ATOMIC);
- if (fl == NULL)
- return NULL;
-
- INIT_LIST_HEAD(&fl->list);
-
- fl->proc = proc;
- fl->pfg = pfg;
- fl->pfg_is_inst = false;
-
- return fl;
-}
-
-void sspt_filter_free(struct sspt_filter *fl)
-{
- if (fl->pfg_is_inst) {
- struct pfg_msg_cb *cb = pfg_msg_cb_get(fl->pfg);
-
- if (cb && cb->msg_term)
- cb->msg_term(fl->proc->task);
- }
-
- kfree(fl);
-}
+++ /dev/null
-#ifndef __SSPT_FILTER_H__
-#define __SSPT_FILTER_H__
-
-#include <linux/types.h>
-
-struct pf_group;
-struct sspt_proc;
-
-struct sspt_filter {
- struct list_head list;
- struct sspt_proc *proc;
- struct pf_group *pfg;
- bool pfg_is_inst;
-};
-
-struct sspt_filter *sspt_filter_create(struct sspt_proc *proc,
- struct pf_group *pfg);
-void sspt_filter_free(struct sspt_filter *fl);
-
-#endif /* __SSPT_FILTER_H__ */
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * modules/driver/sspt/sspt_page.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include "sspt.h"
-#include "sspt_page.h"
-#include "sspt_file.h"
-#include "ip.h"
-#include <us_manager/probes/use_probes.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-
-/**
- * @brief Create sspt_page struct
- *
- * @param offset File ofset
- * @return Pointer to the created sspt_page struct
- */
-struct sspt_page *sspt_page_create(unsigned long offset)
-{
- struct sspt_page *obj = kmalloc(sizeof(*obj), GFP_ATOMIC);
- if (obj) {
- INIT_LIST_HEAD(&obj->ip_list_inst);
- INIT_LIST_HEAD(&obj->ip_list_no_inst);
- obj->offset = offset;
- spin_lock_init(&obj->lock);
- obj->file = NULL;
- INIT_HLIST_NODE(&obj->hlist);
- }
-
- return obj;
-}
-
-/**
- * @brief Remove sspt_page struct
- *
- * @param page remove object
- * @return Void
- */
-void sspt_page_free(struct sspt_page *page)
-{
- struct us_ip *ip, *n;
-
- list_for_each_entry_safe(ip, n, &page->ip_list_inst, list) {
- list_del(&ip->list);
- free_ip(ip);
- }
-
- list_for_each_entry_safe(ip, n, &page->ip_list_no_inst, list) {
- list_del(&ip->list);
- free_ip(ip);
- }
-
- kfree(page);
-}
-
-static void sspt_list_add_ip(struct sspt_page *page, struct us_ip *ip)
-{
- list_add(&ip->list, &page->ip_list_no_inst);
-}
-
-static void sspt_list_del_ip(struct us_ip *ip)
-{
- list_del(&ip->list);
-}
-
-/**
- * @brief Add instruction pointer to sspt_page
- *
- * @param page Pointer to the sspt_page struct
- * @param ip Pointer to the us_ip struct
- * @return Void
- */
-void sspt_add_ip(struct sspt_page *page, struct us_ip *ip)
-{
- ip->offset &= ~PAGE_MASK;
-
- sspt_list_add_ip(page, ip);
-}
-
-/**
- * @brief Del instruction pointer from sspt_page
- *
- * @param ip Pointer to the us_ip struct
- * @return Void
- */
-void sspt_del_ip(struct us_ip *ip)
-{
- sspt_list_del_ip(ip);
- free_ip(ip);
-}
-
-/**
- * @brief Check if probes are set on the page
- *
- * @param page Pointer to the sspt_page struct
- * @return
- * - 0 - false
- * - 1 - true
- */
-int sspt_page_is_installed(struct sspt_page *page)
-{
- int empty;
-
- spin_lock(&page->lock);
- empty = list_empty(&page->ip_list_inst);
- spin_unlock(&page->lock);
-
- return !empty;
-}
-
-/**
- * @brief Install probes on the page
- *
- * @param page Pointer to the sspt_page struct
- * @param file Pointer to the sspt_file struct
- * @return Error code
- */
-int sspt_register_page(struct sspt_page *page, struct sspt_file *file)
-{
- int err = 0;
- struct us_ip *ip, *n;
- struct list_head ip_list_tmp;
-
- spin_lock(&page->lock);
- if (list_empty(&page->ip_list_no_inst)) {
- struct task_struct *task = page->file->proc->task;
-
- printk(KERN_INFO "page %lx in %s task[tgid=%u, pid=%u] "
- "already installed\n",
- page->offset, file->dentry->d_iname,
- task->tgid, task->pid);
- goto unlock;
- }
-
- INIT_LIST_HEAD(&ip_list_tmp);
- list_replace_init(&page->ip_list_no_inst, &ip_list_tmp);
- spin_unlock(&page->lock);
-
- list_for_each_entry_safe(ip, n, &ip_list_tmp, list) {
- /* set virtual address */
- ip->orig_addr = file->vm_start + page->offset + ip->offset;
-
- err = sspt_register_usprobe(ip);
- if (err) {
- list_del(&ip->list);
- free_ip(ip);
- continue;
- }
- }
-
- spin_lock(&page->lock);
- list_splice(&ip_list_tmp, &page->ip_list_inst);
-
-unlock:
- spin_unlock(&page->lock);
-
- return 0;
-}
-
-/**
- * @brief Uninstall probes on the page
- *
- * @param page Pointer to the sspt_page struct
- * @param flag Action for probes
- * @param task Pointer to the task_struct struct
- * @return Error code
- */
-int sspt_unregister_page(struct sspt_page *page,
- enum US_FLAGS flag,
- struct task_struct *task)
-{
- int err = 0;
- struct us_ip *ip;
- struct list_head ip_list_tmp, *head;
-
- spin_lock(&page->lock);
- if (list_empty(&page->ip_list_inst)) {
- spin_unlock(&page->lock);
- return 0;
- }
-
- INIT_LIST_HEAD(&ip_list_tmp);
- list_replace_init(&page->ip_list_inst, &ip_list_tmp);
-
- spin_unlock(&page->lock);
-
- list_for_each_entry(ip, &ip_list_tmp, list) {
- err = sspt_unregister_usprobe(task, ip, flag);
- if (err != 0) {
- /* TODO: ERROR */
- break;
- }
- }
-
- head = (flag == US_DISARM) ?
- &page->ip_list_inst : &page->ip_list_no_inst;
-
- spin_lock(&page->lock);
-
- list_splice(&ip_list_tmp, head);
- spin_unlock(&page->lock);
-
- return err;
-}
-
-void sspt_page_on_each_ip(struct sspt_page *page,
- void (*func)(struct us_ip *, void *), void *data)
-{
- struct us_ip *ip;
-
- spin_lock(&page->lock);
- list_for_each_entry(ip, &page->ip_list_inst, list)
- func(ip, data);
-
- spin_unlock(&page->lock);
-}
+++ /dev/null
-#ifndef __SSPT_PAGE__
-#define __SSPT_PAGE__
-
-/**
- * @file us_manager/sspt/sspt_page.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-struct us_ip;
-struct sspt_file;
-struct task_struct;
-enum US_FLAGS;
-
-/**
- * @struct sspt_page
- * @breaf Image of page for specified process
- */
-struct sspt_page {
- struct list_head ip_list_inst; /**< For installed ip */
- struct list_head ip_list_no_inst; /**< For don'tinstalled ip */
- unsigned long offset; /**< File offset */
- spinlock_t lock; /**< Lock page */
-
- struct sspt_file *file; /**< Ptr to the file(parent)=*/
- struct hlist_node hlist; /**< For sspt_file */
-};
-
-struct sspt_page *sspt_page_create(unsigned long offset);
-void sspt_page_free(struct sspt_page *page);
-
-void sspt_add_ip(struct sspt_page *page, struct us_ip *ip);
-void sspt_del_ip(struct us_ip *ip);
-
-int sspt_page_is_installed(struct sspt_page *page);
-
-int sspt_register_page(struct sspt_page *page, struct sspt_file *file);
-
-int sspt_unregister_page(struct sspt_page *page,
- enum US_FLAGS flag,
- struct task_struct *task);
-
-void sspt_page_on_each_ip(struct sspt_page *page,
- void (*func)(struct us_ip *, void *), void *data);
-
-#endif /* __SSPT_PAGE__ */
+++ /dev/null
-/*
- * Dynamic Binary Instrumentation Module based on KProbes
- * modules/driver/sspt/sspt_proc.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-#include "sspt.h"
-#include "sspt_proc.h"
-#include "sspt_page.h"
-#include "sspt_feature.h"
-#include "sspt_filter.h"
-#include "../pf/proc_filters.h"
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <us_manager/us_slot_manager.h>
-
-static LIST_HEAD(proc_probes_list);
-static DEFINE_RWLOCK(sspt_proc_rwlock);
-
-
-struct list_head *sspt_proc_list()
-{
- return &proc_probes_list;
-}
-
-/**
- * @brief Global read lock for sspt_proc
- *
- * @return Void
- */
-void sspt_proc_read_lock(void)
-{
- read_lock(&sspt_proc_rwlock);
-}
-
-/**
- * @brief Global read unlock for sspt_proc
- *
- * @return Void
- */
-void sspt_proc_read_unlock(void)
-{
- read_unlock(&sspt_proc_rwlock);
-}
-
-/**
- * @brief Global write lock for sspt_proc
- *
- * @return Void
- */
-void sspt_proc_write_lock(void)
-{
- write_lock(&sspt_proc_rwlock);
-}
-
-/**
- * @brief Global write unlock for sspt_proc
- *
- * @return Void
- */
-void sspt_proc_write_unlock(void)
-{
- write_unlock(&sspt_proc_rwlock);
-}
-
-
-/**
- * @brief Create sspt_proc struct
- *
- * @param task Pointer to the task_struct struct
- * @param priv Private data
- * @return Pointer to the created sspt_proc struct
- */
-struct sspt_proc *sspt_proc_create(struct task_struct *task)
-{
- struct sspt_proc *proc = kzalloc(sizeof(*proc), GFP_ATOMIC);
-
- if (proc) {
- proc->feature = sspt_create_feature();
- if (proc->feature == NULL) {
- kfree(proc);
- return NULL;
- }
-
- INIT_LIST_HEAD(&proc->list);
- proc->tgid = task->tgid;
- proc->task = task->group_leader;
- proc->sm = create_sm_us(task);
- INIT_LIST_HEAD(&proc->file_list);
- rwlock_init(&proc->filter_lock);
- INIT_LIST_HEAD(&proc->filter_list);
- atomic_set(&proc->usage, 1);
-
- get_task_struct(proc->task);
-
- /* add to list */
- list_add(&proc->list, &proc_probes_list);
- }
-
- return proc;
-}
-
-/**
- * @brief Remove sspt_proc struct
- *
- * @param proc remove object
- * @return Void
- */
-
-/* called with sspt_proc_write_lock() */
-void sspt_proc_cleanup(struct sspt_proc *proc)
-{
- struct sspt_file *file, *n;
-
- sspt_proc_del_all_filters(proc);
-
- list_for_each_entry_safe(file, n, &proc->file_list, list) {
- list_del(&file->list);
- sspt_file_free(file);
- }
-
- sspt_destroy_feature(proc->feature);
-
- free_sm_us(proc->sm);
- sspt_proc_put(proc);
-}
-
-struct sspt_proc *sspt_proc_get(struct sspt_proc *proc)
-{
- atomic_inc(&proc->usage);
-
- return proc;
-}
-
-void sspt_proc_put(struct sspt_proc *proc)
-{
- if (atomic_dec_and_test(&proc->usage)) {
- if (proc->__mm) {
- mmput(proc->__mm);
- proc->__mm = NULL;
- }
- if (proc->__task) {
- put_task_struct(proc->__task);
- proc->__task = NULL;
- }
-
- put_task_struct(proc->task);
- kfree(proc);
- }
-}
-
-struct sspt_proc *sspt_proc_get_by_task(struct task_struct *task)
-{
- struct sspt_proc *proc;
-
- sspt_proc_read_lock();
- proc = sspt_proc_get_by_task_no_lock(task);
- sspt_proc_read_unlock();
-
- return proc;
-}
-EXPORT_SYMBOL_GPL(sspt_proc_get_by_task);
-
-/**
- * @brief Get sspt_proc by task
- *
- * @param task Pointer on the task_struct struct
- * @return Pointer on the sspt_proc struct
- */
-struct sspt_proc *sspt_proc_get_by_task_no_lock(struct task_struct *task)
-{
- struct sspt_proc *proc, *tmp;
-
- list_for_each_entry_safe(proc, tmp, &proc_probes_list, list) {
- if (proc->tgid == task->tgid)
- return proc;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(sspt_proc_get_by_task_no_lock);
-
-/**
- * @brief Call func() on each proc (no lock)
- *
- * @param func Callback
- * @param data Data for callback
- * @return Void
- */
-void on_each_proc_no_lock(void (*func)(struct sspt_proc *, void *), void *data)
-{
- struct sspt_proc *proc, *tmp;
-
- list_for_each_entry_safe(proc, tmp, &proc_probes_list, list) {
- func(proc, data);
- }
-}
-
-/**
- * @brief Call func() on each proc
- *
- * @param func Callback
- * @param data Data for callback
- * @return Void
- */
-void on_each_proc(void (*func)(struct sspt_proc *, void *), void *data)
-{
- sspt_proc_read_lock();
- on_each_proc_no_lock(func, data);
- sspt_proc_read_unlock();
-}
-EXPORT_SYMBOL_GPL(on_each_proc);
-
-/**
- * @brief Get sspt_proc by task or create sspt_proc
- *
- * @param task Pointer on the task_struct struct
- * @param priv Private data
- * @return Pointer on the sspt_proc struct
- */
-struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task)
-{
- struct sspt_proc *proc;
-
- sspt_proc_write_lock();
- proc = sspt_proc_get_by_task_no_lock(task);
- if (proc == NULL)
- proc = sspt_proc_create(task);
- sspt_proc_write_unlock();
-
- return proc;
-}
-
-/**
- * @brief Free all sspt_proc
- *
- * @return Pointer on the sspt_proc struct
- */
-void sspt_proc_free_all(void)
-{
- struct sspt_proc *proc, *n;
-
- list_for_each_entry_safe(proc, n, &proc_probes_list, list) {
- list_del(&proc->list);
- sspt_proc_cleanup(proc);
- }
-}
-
-static void sspt_proc_add_file(struct sspt_proc *proc, struct sspt_file *file)
-{
- list_add(&file->list, &proc->file_list);
- file->proc = proc;
-}
-
-/**
- * @brief Get sspt_file from sspt_proc by dentry or new
- *
- * @param proc Pointer on the sspt_proc struct
- * @param dentry Dentry of file
- * @return Pointer on the sspt_file struct
- */
-struct sspt_file *sspt_proc_find_file_or_new(struct sspt_proc *proc,
- struct dentry *dentry)
-{
- struct sspt_file *file;
-
- file = sspt_proc_find_file(proc, dentry);
- if (file == NULL) {
- file = sspt_file_create(dentry, 10);
- if (file)
- sspt_proc_add_file(proc, file);
- }
-
- return file;
-}
-
-/**
- * @brief Get sspt_file from sspt_proc by dentry
- *
- * @param proc Pointer on the sspt_proc struct
- * @param dentry Dentry of file
- * @return Pointer on the sspt_file struct
- */
-struct sspt_file *sspt_proc_find_file(struct sspt_proc *proc,
- struct dentry *dentry)
-{
- struct sspt_file *file;
-
- list_for_each_entry(file, &proc->file_list, list) {
- if (dentry == file->dentry)
- return file;
- }
-
- return NULL;
-}
-
-void sspt_proc_install_probe(struct sspt_proc *proc, unsigned long vaddr,
- struct probe_info *probe_i)
-{
- struct vm_area_struct *vma;
- struct task_struct *task = proc->task;
- struct mm_struct *mm = task->mm;
- unsigned long page_vaddr = vaddr & PAGE_MASK;
-
- vma = find_vma_intersection(mm, page_vaddr, page_vaddr + 1);
- if (vma && check_vma(vma)) {
- struct sspt_file *file;
- struct dentry *dentry = vma->vm_file->f_dentry;
-
- file = sspt_proc_find_file_or_new(proc, dentry);
- if (file) {
- unsigned long addr = vaddr - vma->vm_start;
- struct sspt_page *page;
-
- sspt_file_set_mapping(file, vma);
- sspt_file_add_ip(file, addr, probe_i);
-
- page = sspt_find_page_mapped(file, page_vaddr);
- if (page)
- sspt_register_page(page, file);
- }
- }
-}
-EXPORT_SYMBOL_GPL(sspt_proc_install_probe);
-
-/**
- * @brief Install probes on the page to monitored process
- *
- * @param proc Pointer on the sspt_proc struct
- * @param page_addr Page address
- * @return Void
- */
-void sspt_proc_install_page(struct sspt_proc *proc, unsigned long page_addr)
-{
- struct mm_struct *mm = proc->task->mm;
- struct vm_area_struct *vma;
-
- vma = find_vma_intersection(mm, page_addr, page_addr + 1);
- if (vma && check_vma(vma)) {
- struct dentry *dentry = vma->vm_file->f_dentry;
- struct sspt_file *file = sspt_proc_find_file(proc, dentry);
- if (file) {
- struct sspt_page *page;
-
- sspt_file_set_mapping(file, vma);
-
- page = sspt_find_page_mapped(file, page_addr);
- if (page)
- sspt_register_page(page, file);
- }
- }
-}
-
-/**
- * @brief Install probes to monitored process
- *
- * @param proc Pointer on the sspt_proc struct
- * @return Void
- */
-void sspt_proc_install(struct sspt_proc *proc)
-{
- struct vm_area_struct *vma;
- struct mm_struct *mm = proc->task->mm;
-
- proc->first_install = 1;
-
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- if (check_vma(vma)) {
- struct dentry *dentry = vma->vm_file->f_dentry;
- struct sspt_file *file =
- sspt_proc_find_file(proc, dentry);
- if (file) {
- sspt_file_set_mapping(file, vma);
- sspt_file_install(file);
- }
- }
- }
-}
-
-/**
- * @brief Uninstall probes to monitored process
- *
- * @param proc Pointer on the sspt_proc struct
- * @param task Pointer on the task_struct struct
- * @param flag Action for probes
- * @return Error code
- */
-int sspt_proc_uninstall(struct sspt_proc *proc,
- struct task_struct *task,
- enum US_FLAGS flag)
-{
- int err = 0;
- struct sspt_file *file;
-
- list_for_each_entry_rcu(file, &proc->file_list, list) {
- err = sspt_file_uninstall(file, task, flag);
- if (err != 0) {
- printk(KERN_INFO "ERROR sspt_proc_uninstall: err=%d\n",
- err);
- return err;
- }
- }
-
- return err;
-}
-
-static int intersection(unsigned long start_a, unsigned long end_a,
- unsigned long start_b, unsigned long end_b)
-{
- return start_a < start_b ?
- end_a > start_b :
- start_a < end_b;
-}
-
-/**
- * @brief Get sspt_file list by region (remove sspt_file from sspt_proc list)
- *
- * @param proc Pointer on the sspt_proc struct
- * @param head[out] Pointer on the head list
- * @param start Region start
- * @param len Region length
- * @return Error code
- */
-int sspt_proc_get_files_by_region(struct sspt_proc *proc,
- struct list_head *head,
- unsigned long start, size_t len)
-{
- int ret = 0;
- struct sspt_file *file, *n;
- unsigned long end = start + len;
-
- list_for_each_entry_safe(file, n, &proc->file_list, list) {
- if (intersection(file->vm_start, file->vm_end, start, end)) {
- ret = 1;
- list_move(&file->list, head);
- }
- }
-
- return ret;
-}
-
-/**
- * @brief Insert sspt_file to sspt_proc list
- *
- * @param proc Pointer on the sspt_proc struct
- * @param head Pointer on the head list
- * @return Void
- */
-void sspt_proc_insert_files(struct sspt_proc *proc, struct list_head *head)
-{
- list_splice(head, &proc->file_list);
-}
-
-/**
- * @brief Add sspt_filter to sspt_proc list
- *
- * @param proc Pointer to sspt_proc struct
- * @param pfg Pointer to pf_group struct
- * @return Void
- */
-void sspt_proc_add_filter(struct sspt_proc *proc, struct pf_group *pfg)
-{
- struct sspt_filter *f;
-
- f = sspt_filter_create(proc, pfg);
- if (f)
- list_add(&f->list, &proc->filter_list);
-}
-
-/**
- * @brief Remove sspt_filter from sspt_proc list
- *
- * @param proc Pointer to sspt_proc struct
- * @param pfg Pointer to pf_group struct
- * @return Void
- */
-void sspt_proc_del_filter(struct sspt_proc *proc, struct pf_group *pfg)
-{
- struct sspt_filter *fl, *tmp;
-
- write_lock(&proc->filter_lock);
- list_for_each_entry_safe(fl, tmp, &proc->filter_list, list) {
- if (fl->pfg == pfg) {
- list_del(&fl->list);
- sspt_filter_free(fl);
- }
- }
- write_unlock(&proc->filter_lock);
-}
-
-/**
- * @brief Remove all sspt_filters from sspt_proc list
- *
- * @param proc Pointer to sspt_proc struct
- * @return Void
- */
-void sspt_proc_del_all_filters(struct sspt_proc *proc)
-{
- struct sspt_filter *fl, *tmp;
-
- write_lock(&proc->filter_lock);
- list_for_each_entry_safe(fl, tmp, &proc->filter_list, list) {
- list_del(&fl->list);
- sspt_filter_free(fl);
- }
- write_unlock(&proc->filter_lock);
-}
-
-/**
- * @brief Check if sspt_filter is already in sspt_proc list
- *
- * @param proc Pointer to sspt_proc struct
- * @param pfg Pointer to pf_group struct
- * @return Boolean
- */
-bool sspt_proc_is_filter_new(struct sspt_proc *proc, struct pf_group *pfg)
-{
- struct sspt_filter *fl;
-
- list_for_each_entry(fl, &proc->filter_list, list)
- if (fl->pfg == pfg)
- return false;
-
- return true;
-}
-
-void sspt_proc_on_each_filter(struct sspt_proc *proc,
- void (*func)(struct sspt_filter *, void *),
- void *data)
-{
- struct sspt_filter *fl;
-
- list_for_each_entry(fl, &proc->filter_list, list)
- func(fl, data);
-}
-
-void sspt_proc_on_each_ip(struct sspt_proc *proc,
- void (*func)(struct us_ip *, void *), void *data)
-{
- struct sspt_file *file;
-
- list_for_each_entry(file, &proc->file_list, list)
- sspt_file_on_each_ip(file, func, data);
-}
-
-static void is_send_event(struct sspt_filter *f, void *data)
-{
- bool *is_send = (bool *)data;
-
- if (!*is_send && f->pfg_is_inst)
- *is_send = !!pfg_msg_cb_get(f->pfg);
-}
-
-bool sspt_proc_is_send_event(struct sspt_proc *proc)
-{
- bool is_send = false;
-
- /* FIXME: add read lock (deadlock in sampler) */
- sspt_proc_on_each_filter(proc, is_send_event, (void *)&is_send);
-
- return is_send;
-}
-
-
-static struct sspt_proc_cb *proc_cb;
-
-int sspt_proc_cb_set(struct sspt_proc_cb *cb)
-{
- if (cb && proc_cb)
- return -EBUSY;
-
- proc_cb = cb;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(sspt_proc_cb_set);
-
-void sspt_proc_priv_create(struct sspt_proc *proc)
-{
- if (proc_cb && proc_cb->priv_create)
- proc->private_data = proc_cb->priv_create(proc);
-}
-
-void sspt_proc_priv_destroy(struct sspt_proc *proc)
-{
- if (proc->first_install && proc_cb && proc_cb->priv_destroy)
- proc_cb->priv_destroy(proc, proc->private_data);
-}
+++ /dev/null
-#ifndef __SSPT_PROC__
-#define __SSPT_PROC__
-
-/**
- * @file us_manager/sspt/sspt_proc.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-#include <linux/types.h>
-#include "sspt_file.h"
-
-struct slot_manager;
-struct task_struct;
-struct pf_group;
-struct sspt_filter;
-struct us_ip;
-
-/** Flags for sspt_*_uninstall() */
-enum US_FLAGS {
- US_UNREGS_PROBE, /**< probes remove and disarm */
- US_DISARM, /**< probes disarm */
- US_UNINSTALL /**< probes remove from list install */
-};
-
-/**
- * @struct sspt_proc
- * @breaf Image of process for specified process
- */
-struct sspt_proc {
- struct list_head list; /**< For global process list */
- pid_t tgid; /**< Thread group ID */
- struct task_struct *task; /**< Ptr to the task */
- struct mm_struct *__mm;
- struct task_struct *__task;
- unsigned long r_state_addr; /**< address of r_state */
- struct slot_manager *sm; /**< Ptr to the manager slot */
- struct list_head file_list; /**< For sspt_file */
- rwlock_t filter_lock;
- struct list_head filter_list; /**< Filter list */
- unsigned first_install:1; /**< Install flag */
- struct sspt_feature *feature; /**< Ptr to the feature */
- atomic_t usage;
-
- /* FIXME: for preload (remove those fields) */
- void *private_data; /**< Process private data */
-};
-
-struct sspt_proc_cb {
- void *(*priv_create)(struct sspt_proc *);
- void (*priv_destroy)(struct sspt_proc *, void *);
-};
-
-
-struct list_head *sspt_proc_list(void);
-
-struct sspt_proc *sspt_proc_create(struct task_struct *task);
-void sspt_proc_cleanup(struct sspt_proc *proc);
-struct sspt_proc *sspt_proc_get(struct sspt_proc *proc);
-void sspt_proc_put(struct sspt_proc *proc);
-
-void on_each_proc_no_lock(void (*func)(struct sspt_proc *, void *),
- void *data);
-void on_each_proc(void (*func)(struct sspt_proc *, void *), void *data);
-
-struct sspt_proc *sspt_proc_get_by_task(struct task_struct *task);
-struct sspt_proc *sspt_proc_get_by_task_no_lock(struct task_struct *task);
-struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task);
-void sspt_proc_free_all(void);
-
-struct sspt_file *sspt_proc_find_file(struct sspt_proc *proc,
- struct dentry *dentry);
-struct sspt_file *sspt_proc_find_file_or_new(struct sspt_proc *proc,
- struct dentry *dentry);
-
-void sspt_proc_install_probe(struct sspt_proc *proc, unsigned long vaddr,
- struct probe_info *probe_i);
-void sspt_proc_install_page(struct sspt_proc *proc, unsigned long page_addr);
-void sspt_proc_install(struct sspt_proc *proc);
-int sspt_proc_uninstall(struct sspt_proc *proc,
- struct task_struct *task,
- enum US_FLAGS flag);
-
-int sspt_proc_get_files_by_region(struct sspt_proc *proc,
- struct list_head *head,
- unsigned long start, size_t len);
-void sspt_proc_insert_files(struct sspt_proc *proc, struct list_head *head);
-
-void sspt_proc_read_lock(void);
-void sspt_proc_read_unlock(void);
-void sspt_proc_write_lock(void);
-void sspt_proc_write_unlock(void);
-
-void sspt_proc_add_filter(struct sspt_proc *proc, struct pf_group *pfg);
-void sspt_proc_del_filter(struct sspt_proc *proc, struct pf_group *pfg);
-void sspt_proc_del_all_filters(struct sspt_proc *proc);
-bool sspt_proc_is_filter_new(struct sspt_proc *proc, struct pf_group *pfg);
-
-void sspt_proc_on_each_filter(struct sspt_proc *proc,
- void (*func)(struct sspt_filter *, void *),
- void *data);
-
-void sspt_proc_on_each_ip(struct sspt_proc *proc,
- void (*func)(struct us_ip *, void *), void *data);
-
-bool sspt_proc_is_send_event(struct sspt_proc *proc);
-
-int sspt_proc_cb_set(struct sspt_proc_cb *cb);
-void sspt_proc_priv_create(struct sspt_proc *proc);
-void sspt_proc_priv_destroy(struct sspt_proc *proc);
-
-#endif /* __SSPT_PROC__ */
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/us_manager.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/stop_machine.h>
-#include "pf/pf_group.h"
-#include "sspt/sspt_proc.h"
-#include "probes/probe_info_new.h"
-#include "helper.h"
-#include "us_manager.h"
-#include "debugfs_us_manager.h"
-#include "callbacks.h"
-#include <writer/event_filter.h>
-#include <master/swap_initializer.h>
-
-
-static DEFINE_MUTEX(mutex_inst);
-static enum status_type status = ST_OFF;
-
-
-static int __do_usm_stop(void *data)
-{
- get_all_procs();
-
- return 0;
-}
-
-static int do_usm_stop(void)
-{
- int ret;
-
- exec_cbs(STOP_CB);
- unregister_helper_top();
-
- ret = stop_machine(__do_usm_stop, NULL, NULL);
- if (ret)
- printk("do_usm_stop failed: %d\n", ret);
-
- uninstall_all();
- unregister_helper_bottom();
- sspt_proc_free_all();
- exec_cbs(STOP_CB_TD);
-
- return ret;
-}
-
-static int do_usm_start(void)
-{
- int ret;
-
- ret = register_helper();
- if (ret)
- return ret;
-
- install_all();
-
- exec_cbs(START_CB);
-
- return 0;
-}
-
-/**
- * @brief Get instrumentation status
- *
- * @return Instrumentation status
- */
-enum status_type usm_get_status(void)
-{
- mutex_lock(&mutex_inst);
- return status;
-}
-EXPORT_SYMBOL_GPL(usm_get_status);
-
-/**
- * @brief Put instrumentation status
- *
- * @param st Instrumentation status
- * @return Void
- */
-void usm_put_status(enum status_type st)
-{
- status = st;
- mutex_unlock(&mutex_inst);
-}
-EXPORT_SYMBOL_GPL(usm_put_status);
-
-/**
- * @brief Stop instrumentation
- *
- * @return Error code
- */
-int usm_stop(void)
-{
- int ret = 0;
-
- if (usm_get_status() == ST_OFF) {
- printk(KERN_INFO "US instrumentation is not running!\n");
- ret = -EINVAL;
- goto put;
- }
-
- do_usm_stop();
-
-put:
- usm_put_status(ST_OFF);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(usm_stop);
-
-/**
- * @brief Start instrumentation
- *
- * @return Error code
- */
-int usm_start(void)
-{
- int ret = -EINVAL;
- enum status_type st;
-
- st = usm_get_status();
- if (st == ST_ON) {
- printk(KERN_INFO "US instrumentation is already run!\n");
- goto put;
- }
-
- ret = do_usm_start();
- if (ret == 0)
- st = ST_ON;
-
-put:
- usm_put_status(st);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(usm_start);
-
-
-
-
-
-/* ============================================================================
- * === QUIET ===
- * ============================================================================
- */
-static enum quiet_type quiet = QT_ON;
-
-/**
- * @brief Set quiet mode
- *
- * @param q Quiet mode
- * @return Void
- */
-void set_quiet(enum quiet_type q)
-{
- quiet = q;
-}
-EXPORT_SYMBOL_GPL(set_quiet);
-
-/**
- * @brief Get quiet mode
- *
- * @return Quiet mode
- */
-enum quiet_type get_quiet(void)
-{
- return quiet;
-}
-EXPORT_SYMBOL_GPL(get_quiet);
-
-
-
-
-
-/* ============================================================================
- * === US_FILTER ===
- * ============================================================================
- */
-static int us_filter(struct task_struct *task)
-{
- struct sspt_proc *proc;
-
- /* FIXME: add read lock (deadlock in sampler) */
- proc = sspt_proc_get_by_task_no_lock(task);
- if (proc)
- return sspt_proc_is_send_event(proc);
-
- return 0;
-}
-
-static struct ev_filter ev_us_filter = {
- .name = "traced_process_only",
- .filter = us_filter
-};
-
-static int init_us_filter(void)
-{
- int ret;
-
- ret = event_filter_register(&ev_us_filter);
- if (ret)
- return ret;
-
- return event_filter_set(ev_us_filter.name);
-}
-
-static void exit_us_filter(void)
-{
- event_filter_unregister(&ev_us_filter);
-}
-
-
-
-
-
-static int usm_once(void)
-{
- int ret;
-
- ret = once_helper();
-
- return ret;
-}
-
-static int init_us_manager(void)
-{
- int ret;
-
- ret = pin_init();
- if (ret)
- return ret;
-
- ret = init_us_filter();
- if (ret)
- pin_exit();
-
- return ret;
-}
-
-static void exit_us_manager(void)
-{
- if (status == ST_ON)
- do_usm_stop();
-
- remove_all_cbs();
-
- exit_us_filter();
- pin_exit();
-}
-
-SWAP_LIGHT_INIT_MODULE(usm_once, init_us_manager, exit_us_manager,
- init_debugfs_us_manager, exit_debugfs_us_manager);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/**
- * @file us_manager/us_manager.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-#ifndef _US_MANAGER_H
-#define _US_MANAGER_H
-
-
-/** Quiet mode */
-enum quiet_type {
- QT_ON, /**< Quiet mode - on */
- QT_OFF /**< Quiet mode - off */
-};
-
-/** Instrumentation status */
-enum status_type {
- ST_OFF, /**< Instrumentation status - off */
- ST_ON /**< Instrumentation status - on */
-};
-
-void set_quiet(enum quiet_type q);
-enum quiet_type get_quiet(void);
-
-enum status_type usm_get_status(void);
-void usm_put_status(enum status_type st);
-
-int usm_start(void);
-int usm_stop(void);
-
-#endif /* _US_MANAGER_H */
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/us_slot_manager.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Alexander Aksenov: SWAP us_manager implement
- *
- */
-
-
-#include <linux/mm.h>
-#include <linux/version.h>
-
-/*
- * TODO: move declaration and definition swap_do_mmap_pgoff()
- * from swap_kprobe.ko to swap_us_manager.ko
- */
-#include <kprobe/swap_kprobes_deps.h>
-
-
-static inline unsigned long swap_do_mmap(struct file *filp, unsigned long addr,
- unsigned long len, unsigned long prot,
- unsigned long flag,
- unsigned long offset)
-{
- unsigned long populate;
-
- return swap_do_mmap_pgoff(filp, addr, len, prot,
- flag, offset, &populate);
-}
+++ /dev/null
-/*
- * SWAP uprobe manager
- * modules/us_manager/us_slot_manager.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * 2013 Vyacheslav Cherkashin: SWAP us_manager implement
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/hardirq.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/list.h>
-
-#include <kprobe/swap_slots.h>
-#include <swap-asm/swap_kprobes.h>
-#include "us_manager_common.h"
-
-
-static void *sm_alloc_us(struct slot_manager *sm)
-{
- unsigned long addr;
-
- addr = swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_EXEC|PROT_READ|PROT_WRITE,
- MAP_ANONYMOUS|MAP_PRIVATE, 0);
- return (void *)addr;
-}
-
-static void sm_free_us(struct slot_manager *sm, void *ptr)
-{
- /*
- * E. G.: This code provides kernel dump because of rescheduling while
- * atomic. As workaround, this code was commented. In this case we will
- * have memory leaks for instrumented process, but instrumentation
- * process should functionate correctly. Planned that good solution for
- * this problem will be done during redesigning KProbe for improving
- * supportability and performance.
- */
-#if 0
- struct task_struct *task = sm->data;
-
- mm = get_task_mm(task);
- if (mm) {
- down_write(&mm->mmap_sem);
- do_munmap(mm, (unsigned long)(ptr), PAGE_SIZE);
- up_write(&mm->mmap_sem);
- mmput(mm);
- }
-#endif
- /* FIXME: implement the removal of memory for task */
-}
-
-/**
- * @brief Create slot_manager struct for US
- *
- * @param task Pointer to the task_struct struct
- * @return Pointer to the created slot_manager struct
- */
-struct slot_manager *create_sm_us(struct task_struct *task)
-{
- struct slot_manager *sm = kmalloc(sizeof(*sm), GFP_ATOMIC);
-
- if (sm == NULL)
- return NULL;
-
- sm->slot_size = UPROBES_TRAMP_LEN;
- sm->alloc = sm_alloc_us;
- sm->free = sm_free_us;
- INIT_HLIST_HEAD(&sm->page_list);
- sm->data = task;
-
- return sm;
-}
-
-/**
- * @brief Remove slot_manager struct for US
- *
- * @param sm remove object
- * @return Void
- */
-void free_sm_us(struct slot_manager *sm)
-{
- if (sm == NULL)
- return;
-
- if (!hlist_empty(&sm->page_list)) {
- printk(KERN_WARNING "SWAP US_MANAGER: Error! Slot manager is "
- "not empty!\n");
- return;
- }
-
- kfree(sm);
-}
+++ /dev/null
-/**
- * @file us_manager/us_slot_manager.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2013
- */
-
-
-#ifndef _US_SLOT_MANAGER_H
-#define _US_SLOT_MANAGER_H
-
-struct task_struct;
-struct slot_manager;
-
-struct slot_manager *create_sm_us(struct task_struct *task);
-void free_sm_us(struct slot_manager *sm);
-
-#endif /* _US_SLOT_MANAGER_H */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_webprobe.o
-swap_webprobe-y := webprobe.o \
- webprobe_debugfs.o \
- webprobe_prof.o \
- web_msg.o
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/stddef.h>
-#include <linux/uaccess.h>
-#include <writer/swap_msg.h>
-#include <writer/event_filter.h>
-#include <swap-asm/swap_uprobes.h>
-
-
-#define WEB_PREFIX KERN_INFO "[WEB_PROF] "
-
-/* TODO: develop method for obtaining this data during build... */
-/* location: webkit2-efl-123997_0.11.113/Source/WTF/wtf/text/StringImpl.h:70 */
-struct MStringImpl {
- unsigned m_refCount;
- unsigned m_length;
- union {
- const unsigned char *m_data8;
- const unsigned short *m_data16;
- };
- union {
- void *m_buffer;
- struct MStringImpl *m_substringBuffer;
- unsigned short *m_copyData16;
- };
- unsigned m_hashAndFlags;
-};
-
-/* location: webkit2-efl-123997_0.11.113/Source/JavaScriptCore/profiler/
- * CallIdentifier.h:36
- */
-struct MCallIdentifier {
- struct MStringImpl *m_name;
- struct MStringImpl *m_url;
- unsigned m_lineNumber;
-};
-
-enum {
- OFFSET_NAME = offsetof(struct MCallIdentifier, m_name),
- OFFSET_URL = offsetof(struct MCallIdentifier, m_url),
- OFFSET_LNUM = offsetof(struct MCallIdentifier, m_lineNumber)
-};
-
-
-static int pack_web_string(void *data, size_t size,
- struct MStringImpl __user *str_imp)
-{
- int ret;
- char __user *str;
- unsigned len;
- char __user **pstr;
- unsigned __user *plen;
-
- pstr = (void __user *)str_imp + offsetof(struct MStringImpl, m_data8);
- plen = (void __user *)str_imp + offsetof(struct MStringImpl, m_length);
-
- if (get_user(str, pstr) ||
- get_user(len, plen)) {
- printk(WEB_PREFIX "%s: cannot read user memory\n", __func__);
- return -EPERM;
- }
-
- if (size < len + 1) {
- printk(WEB_PREFIX "function name is very long(len=%u)\n", len);
- return -ENOMEM;
- }
-
- ret = strncpy_from_user(data, str, len);
- if (ret < 0) {
- printk(WEB_PREFIX "%s: cannot read user memory\n", __func__);
- return ret;
- }
-
- ((char *)data)[ret] = '\0';
-
- return ret + 1;
-}
-
-
-void web_msg_entry(struct pt_regs *regs)
-{
- int ret;
- struct swap_msg *m;
- void *p;
- long t_name, t_url;
- unsigned lnum;
- size_t pack_size = 0, size;
- struct MCallIdentifier *call_id;
- struct task_struct *task = current;
-
- if (!check_event(task))
- return;
-
- call_id = (void *)swap_get_uarg(regs, 2);
- if (get_user(t_name, (long *)((long)call_id + OFFSET_NAME)) ||
- get_user(t_url, (long *)((long)call_id + OFFSET_URL)) ||
- get_user(lnum, (unsigned *)((long)call_id + OFFSET_LNUM))) {
- printk(WEB_PREFIX "%s: cannot read user memory\n", __func__);
- return;
- }
-
- m = swap_msg_get(MSG_WEB_FUNCTION_ENTRY);
- p = swap_msg_payload(m);
- size = swap_msg_size(m);
-
- /* Pack message */
- /* PID */
- *(u32 *)p = task->tgid;
- p += sizeof(u32);
- /* TID */
- *(u32 *)p = task->pid;
- p += sizeof(u32);
- /* Line number (in source file) */
- *(u32 *)p = lnum;
- p += sizeof(u32);
-
- size -= 3 * sizeof(u32);
- pack_size += 3 * sizeof(u32);
-
- /* Function name */
- ret = pack_web_string(p, size, (struct MStringImpl *)t_name);
- if (ret < 0)
- goto put_msg;
-
- p += ret;
- size -= ret;
- pack_size += ret;
-
- /* URL (source file) */
- ret = pack_web_string(p, size, (struct MStringImpl *)t_url);
- if (ret < 0)
- goto put_msg;
-
- swap_msg_flush(m, pack_size + ret);
-
-put_msg:
- swap_msg_put(m);
-}
-
-void web_msg_exit(struct pt_regs *regs)
-{
- int ret;
- struct swap_msg *m;
- void *p;
- long t_name;
- size_t pack_size = 0, size;
- struct MCallIdentifier *call_id;
- struct task_struct *task = current;
-
- if (!check_event(task))
- return;
-
- call_id = (void *)swap_get_uarg(regs, 2);
- if (get_user(t_name, (long *)((long)call_id + OFFSET_NAME))) {
- printk(WEB_PREFIX "%s: cannot read user memory\n", __func__);
- return;
- }
-
- m = swap_msg_get(MSG_WEB_FUNCTION_EXIT);
- p = swap_msg_payload(m);
- size = swap_msg_size(m);
-
- /* PID */
- *(u32 *)p = task->tgid;
- p += sizeof(u32);
-
- /* TID */
- *(u32 *)p = task->pid;
- p += sizeof(u32);
-
- size -= 2 * sizeof(u32);
- pack_size += 2 * sizeof(u32);
-
- /* Function name */
- ret = pack_web_string(p, size, (struct MStringImpl *)t_name);
- if (ret < 0)
- goto put_msg;
-
- swap_msg_flush(m, pack_size + ret);
-
-put_msg:
- swap_msg_put(m);
-}
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _WEB_MSG_H
-#define _WEB_MSG_H
-
-
-struct pt_regs;
-
-
-void web_msg_entry(struct pt_regs *regs);
-void web_msg_exit(struct pt_regs *regs);
-
-
-#endif /* _WEB_MSG_H */
+++ /dev/null
-/**
- * webprobe/webprobe.c
- * @author Ruslan Soloviev
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * @section DESCRIPTION
- *
- * Web application profiling
- */
-
-
-#include <us_manager/us_manager.h>
-#include <us_manager/sspt/ip.h>
-#include <us_manager/probes/register_probes.h>
-#include <us_manager/sspt/sspt.h>
-#include <uprobe/swap_uprobes.h>
-#include <parser/msg_cmd.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <master/swap_initializer.h>
-
-#include "webprobe_debugfs.h"
-#include "webprobe_prof.h"
-#include "web_msg.h"
-
-
-static unsigned long inspserver_addr_local;
-static unsigned long willexecute_addr_local;
-static unsigned long didexecute_addr_local;
-
-static int webprobe_copy(struct probe_info *dest,
- const struct probe_info *source)
-{
- memcpy(dest, source, sizeof(*source));
-
- return 0;
-}
-
-static void webprobe_cleanup(struct probe_info *probe_i)
-{
-}
-
-static struct uprobe *webprobe_get_uprobe(struct us_ip *ip)
-{
- return &ip->retprobe.up;
-}
-
-static int webprobe_register_probe(struct us_ip *ip)
-{
- return swap_register_uretprobe(&ip->retprobe);
-}
-
-static void webprobe_unregister_probe(struct us_ip *ip, int disarm)
-{
- if (ip->orig_addr == inspserver_addr_local)
- web_func_inst_remove(web_prof_addr(INSPSERVER_START));
- else if (ip->orig_addr == willexecute_addr_local)
- web_func_inst_remove(web_prof_addr(WILL_EXECUTE));
- else if (ip->orig_addr == didexecute_addr_local)
- web_func_inst_remove(web_prof_addr(DID_EXECUTE));
-
- __swap_unregister_uretprobe(&ip->retprobe, disarm);
-}
-
-static int web_entry_handler(struct uretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct uretprobe *rp = ri->rp;
- struct us_ip *ip;
- unsigned long vaddr, page_vaddr;
- struct vm_area_struct *vma;
-
- if (rp == NULL)
- return 0;
-
- ip = container_of(rp, struct us_ip, retprobe);
- vaddr = (unsigned long)ip->orig_addr;
- page_vaddr = vaddr & PAGE_MASK;
-
- vma = find_vma_intersection(current->mm, page_vaddr, page_vaddr + 1);
- if (vma && check_vma(vma)) {
- unsigned long addr = vaddr - vma->vm_start;
- struct dentry *d = vma->vm_file->f_dentry;
-
- if (addr == web_prof_addr(WILL_EXECUTE) &&
- d == web_prof_lib_dentry()) {
- willexecute_addr_local = ip->orig_addr;
- web_msg_entry(regs);
- } else if (addr == web_prof_addr(DID_EXECUTE) &&
- d == web_prof_lib_dentry()) {
- didexecute_addr_local = ip->orig_addr;
- web_msg_exit(regs);
- }
- }
-
- return 0;
-}
-
-
-static int web_ret_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct uretprobe *rp = ri->rp;
- struct us_ip *ip;
- unsigned long vaddr, page_vaddr;
- struct vm_area_struct *vma;
-
- if (rp == NULL)
- return 0;
-
- ip = container_of(rp, struct us_ip, retprobe);
- vaddr = (unsigned long)ip->orig_addr;
- page_vaddr = vaddr & PAGE_MASK;
-
- vma = find_vma_intersection(current->mm, page_vaddr, page_vaddr + 1);
- if (vma && check_vma(vma)) {
- unsigned long addr = vaddr - vma->vm_start;
- struct dentry *d = vma->vm_file->f_dentry;
-
- if (addr == web_prof_addr(INSPSERVER_START) &&
- d == web_prof_lib_dentry()) {
- inspserver_addr_local = ip->orig_addr;
- set_wrt_launcher_port((int)regs_return_value(regs));
- }
- }
-
- return 0;
-}
-
-static void webprobe_init(struct us_ip *ip)
-{
- ip->retprobe.entry_handler = web_entry_handler;
- ip->retprobe.handler = web_ret_handler;
- ip->retprobe.maxactive = 0;
-}
-
-static void webprobe_uninit(struct us_ip *ip)
-{
- webprobe_cleanup(ip->info);
-}
-
-
-static struct probe_iface webprobe_iface = {
- .init = webprobe_init,
- .uninit = webprobe_uninit,
- .reg = webprobe_register_probe,
- .unreg = webprobe_unregister_probe,
- .get_uprobe = webprobe_get_uprobe,
- .copy = webprobe_copy,
- .cleanup = webprobe_cleanup
-};
-
-static int webprobe_module_init(void)
-{
- int ret = 0;
-
- ret = swap_register_probe_type(SWAP_WEBPROBE, &webprobe_iface);
- if (ret)
- pr_err("Cannot register probe type SWAP_WEBPROBE\n");
-
- return ret;
-}
-
-static void webprobe_module_exit(void)
-{
- swap_unregister_probe_type(SWAP_WEBPROBE);
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, webprobe_module_init, webprobe_module_exit,
- webprobe_debugfs_init, webprobe_debugfs_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP webprobe");
-MODULE_AUTHOR("Ruslan Soloviev <r.soloviev@samsung.com>"
- "Anastasia Lyupa <a.lyupa@samsung.com>");
+++ /dev/null
-/**
- * webprobe/webprobe_debugfs.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Anastasia Lyupa <a.lyupa@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-
-#include <master/swap_debugfs.h>
-#include <master/swap_initializer.h>
-
-#include "webprobe_debugfs.h"
-#include "webprobe_prof.h"
-
-static const char ENABLED_FILE[] = "enabled";
-static const char APP_INFO_FILE[] = "app_info";
-static const char INSPSERVER_START_FILE[] = "inspector_server_start";
-static const char WILL_EXECUTE_FILE[] = "will_execute";
-static const char DID_EXECUTE_FILE[] = "did_execute";
-
-enum { max_count = 256 };
-static char app_info[max_count];
-
-/* ============================================================================
- * === DEBUGFS FOR WEBPROBE INSTRUMENTATION ===
- * ============================================================================
- */
-
-static ssize_t read_enabled(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- char buf[2];
-
- buf[0] = web_prof_enabled() == PROF_ON ? '1' : '0';
- buf[1] = '\n';
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
-}
-
-static ssize_t write_enabled(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- int ret = 0;
- char buf[32];
- size_t buf_size;
-
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
-
- buf[buf_size] = '\0';
- switch (buf[0]) {
- case '1':
- ret = web_prof_enable();
- break;
- case '0':
- ret = web_prof_disable();
- break;
- default:
- return -EINVAL;
- }
-
- if (ret)
- return ret;
-
- return count;
-}
-
-static const struct file_operations fops_enabled = {
- .write = write_enabled,
- .read = read_enabled,
- .open = swap_init_simple_open,
- .release = swap_init_simple_release,
-};
-
-static ssize_t write_app_info(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- int ret = 0;
- char *buf, *path, *id;
- int n;
-
- if (count > max_count)
- return -ENOMEM;
-
- buf = kmalloc(count + 1, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- if (copy_from_user(buf, user_buf, count)) {
- ret = -EFAULT;
- goto free_buf;
- }
-
- buf[count] = '\0';
-
- path = kmalloc(count, GFP_KERNEL);
- if (path == NULL) {
- ret = -ENOMEM;
- goto free_buf;
- }
-
- id = kmalloc(count, GFP_KERNEL);
- if (id == NULL) {
- ret = -ENOMEM;
- goto free_path;
- }
-
- n = sscanf(buf, "%s %s", path, id);
-
- if (n != 2) {
- ret = -EINVAL;
- goto free_app_info;
- }
-
- web_prof_data_set(path, id);
- snprintf(app_info, sizeof(app_info), "%s\n", buf);
-
-free_app_info:
- kfree(id);
-free_path:
- kfree(path);
-free_buf:
- kfree(buf);
-
- return ret ? ret : count;
-}
-
-static ssize_t read_app_info(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- return simple_read_from_buffer(userbuf, count, ppos, app_info,
- sizeof(app_info) - 1);
-}
-
-static const struct file_operations fops_app_info = {
- .write = write_app_info,
- .read = read_app_info,
- .open = swap_init_simple_open,
- .release = swap_init_simple_release,
-};
-
-
-/* ============================================================================
- * === INIT/EXIT ===
- * ============================================================================
- */
-
-static struct dentry *webprobe_dir;
-
-void webprobe_debugfs_exit(void)
-{
- web_prof_exit();
-
- debugfs_remove_recursive(webprobe_dir);
-
- webprobe_dir = NULL;
-}
-
-int webprobe_debugfs_init(void)
-{
- struct dentry *dentry;
-
- if (web_prof_init())
- goto fail;
-
- dentry = swap_debugfs_getdir();
- if (dentry == NULL)
- return -ENOENT;
-
- webprobe_dir = debugfs_create_dir("webprobe", dentry);
- if (webprobe_dir == NULL)
- return -ENOMEM;
-
- dentry = debugfs_create_file(ENABLED_FILE, 0600, webprobe_dir, NULL,
- &fops_enabled);
-
- dentry = debugfs_create_file(APP_INFO_FILE, 0600, webprobe_dir,
- NULL, &fops_app_info);
- if (dentry == NULL)
- goto fail;
-
- dentry = debugfs_create_x64(INSPSERVER_START_FILE, 0600, webprobe_dir,
- web_prof_addr_ptr(INSPSERVER_START));
- if (dentry == NULL)
- goto fail;
-
- dentry = debugfs_create_x64(WILL_EXECUTE_FILE, 0600, webprobe_dir,
- web_prof_addr_ptr(WILL_EXECUTE));
- if (dentry == NULL)
- goto fail;
-
- dentry = debugfs_create_x64(DID_EXECUTE_FILE, 0600, webprobe_dir,
- web_prof_addr_ptr(DID_EXECUTE));
- if (dentry == NULL)
- goto fail;
-
- return 0;
-
-fail:
- webprobe_debugfs_exit();
- return -ENOMEM;
-}
+++ /dev/null
-#ifndef _WEBPROBE_DEBUGFS_H
-#define _WEBPROBE_DEBUGFS_H
-
-/**
- * @file webprobe/webprobe_debugfs.h
- * @author Anastasia Lyupa <a.lyupa@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- * Debugfs for webprobe
- */
-
-
-int webprobe_debugfs_init(void);
-void webprobe_debugfs_exit(void);
-
-
-#endif /* _WEBPROBE_DEBUGFS_H */
+++ /dev/null
-/**
- * webprobe/webprobe_prof.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Anastasia Lyupa <a.lyupa@samsung.com>
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-
-#include <us_manager/pf/pf_group.h>
-#include <us_manager/probes/probes.h>
-
-#include "webprobe_prof.h"
-
-
-static DEFINE_MUTEX(mutex_enable);
-
-struct web_prof_data {
- struct dentry *app_dentry;
- struct dentry *lib_dentry;
- struct pf_group *pfg;
- u64 inspserver_addr;
- u64 willexecute_addr;
- u64 didexecute_addr;
- enum web_prof_state_t enabled;
-};
-
-static const char *LIBEWEBKIT2_PATH = "/usr/lib/libewebkit2.so.0";
-static struct web_prof_data *web_data;
-
-
-u64 *web_prof_addr_ptr(enum web_prof_addr_t type)
-{
- u64 *addr_ptr;
-
- switch (type) {
- case INSPSERVER_START:
- addr_ptr = &web_data->inspserver_addr;
- break;
- case WILL_EXECUTE:
- addr_ptr = &web_data->willexecute_addr;
- break;
- case DID_EXECUTE:
- addr_ptr = &web_data->didexecute_addr;
- break;
- default:
- pr_err("ERROR: WEB_PROF_ADDR_PTR_TYPE=0x%x\n", type);
- addr_ptr = NULL;
- }
-
- return addr_ptr;
-}
-
-unsigned long web_prof_addr(enum web_prof_addr_t type)
-{
- unsigned long addr;
-
- switch (type) {
- case INSPSERVER_START:
- addr = web_data->inspserver_addr;
- break;
- case WILL_EXECUTE:
- addr = web_data->willexecute_addr;
- break;
- case DID_EXECUTE:
- addr = web_data->didexecute_addr;
- break;
- default:
- pr_err("ERROR: WEB_PROF_ADDR_TYPE=0x%x\n", type);
- addr = 0;
- }
-
- return addr;
-}
-
-static int web_func_inst_add(unsigned long addr)
-{
- int ret;
- struct probe_info probe;
-
- probe.probe_type = SWAP_WEBPROBE;
- probe.size = 0;
-
- ret = pf_register_probe(web_data->pfg, web_data->lib_dentry,
- addr, &probe);
-
- return ret;
-}
-
-int web_func_inst_remove(unsigned long addr)
-{
- int ret;
-
- /* FIXME: check that address needs removing */
- ret = pf_unregister_probe(web_data->pfg, web_data->lib_dentry,
- addr);
-
- return ret;
-}
-
-int web_prof_data_set(char *app_path, char *app_id)
-{
- web_data->app_dentry = dentry_by_path(app_path);
- if (web_data->app_dentry == NULL)
- return -EFAULT;
-
- web_data->lib_dentry = dentry_by_path(LIBEWEBKIT2_PATH);
- if (web_data->lib_dentry == NULL)
- return -EFAULT;
-
- if (web_data->pfg)
- put_pf_group(web_data->pfg);
-
- web_data->pfg = get_pf_group_by_comm(app_id, web_data->app_dentry);
- if (web_data->pfg == NULL)
- return -EFAULT;
-
- return 0;
-}
-
-struct dentry *web_prof_lib_dentry(void)
-{
- return web_data->lib_dentry;
-}
-
-enum web_prof_state_t web_prof_enabled(void)
-{
- return web_data->enabled;
-}
-
-int web_prof_enable(void)
-{
- int ret = 0;
-
- mutex_lock(&mutex_enable);
- if (web_data->enabled == PROF_OFF) {
- web_data->enabled = PROF_ON;
-
- if ((web_data->inspserver_addr == 0) ||
- (web_data->willexecute_addr == 0) ||
- (web_data->didexecute_addr == 0)) {
- pr_err("ERROR: Can't enable web profiling\n");
- ret = -EFAULT;
- } else {
- web_func_inst_add(web_data->inspserver_addr);
- web_func_inst_add(web_data->willexecute_addr);
- web_func_inst_add(web_data->didexecute_addr);
- }
- } else {
- pr_err("ERROR: Web profiling is already enabled\n");
- }
- mutex_unlock(&mutex_enable);
-
- return ret;
-}
-
-int web_prof_disable(void)
-{
- int ret = 0;
-
- mutex_lock(&mutex_enable);
- if (web_data->enabled == PROF_ON) {
- web_data->enabled = PROF_OFF;
-
- if ((web_data->inspserver_addr == 0) ||
- (web_data->willexecute_addr == 0) ||
- (web_data->didexecute_addr == 0)) {
- pr_err("ERROR: Can't disable web profiling\n");
- ret = -EFAULT;
- } else {
- web_func_inst_remove(web_data->inspserver_addr);
- web_func_inst_remove(web_data->willexecute_addr);
- web_func_inst_remove(web_data->didexecute_addr);
- }
- } else {
- pr_err("ERROR: Web profiling is already disabled\n");
- }
- mutex_unlock(&mutex_enable);
-
- return ret;
-}
-
-int web_prof_init(void)
-{
- web_data = kmalloc(sizeof(*web_data), GFP_KERNEL);
- if (web_data == NULL)
- return -ENOMEM;
-
- memset(web_data, 0, sizeof(struct web_prof_data));
-
- web_data->enabled = PROF_OFF;
-
- return 0;
-}
-
-
-void web_prof_exit(void)
-{
- if (web_data->pfg)
- put_pf_group(web_data->pfg);
-
- kfree(web_data);
-}
+++ /dev/null
-#ifndef _WEBPROBE_PROF_H
-#define _WEBPROBE_PROF_H
-
-/**
- * @file webprobe/webprobe_prof.h
- * @author Anastasia Lyupa <a.lyupa@samsung.com>
- *
- * @section LICENSE
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- * Copyright (C) Samsung Electronics, 2015
- *
- * @section DESCRIPTION
- * Profiling for webprobe
- */
-
-
-enum web_prof_addr_t {
- INSPSERVER_START = 1,
- WILL_EXECUTE = 2,
- DID_EXECUTE = 3
-};
-
-enum web_prof_state_t {
- PROF_OFF,
- PROF_ON
-};
-
-int web_prof_init(void);
-void web_prof_exit(void);
-int web_prof_enable(void);
-int web_prof_disable(void);
-enum web_prof_state_t web_prof_enabled(void);
-int web_func_inst_remove(unsigned long addr);
-u64 *web_prof_addr_ptr(enum web_prof_addr_t type);
-unsigned long web_prof_addr(enum web_prof_addr_t type);
-int web_prof_data_set(char *app_path, char *app_id);
-struct dentry *web_prof_lib_dentry(void);
-
-#endif /* _WEBPROBE_PROF_H */
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_writer.o
-swap_writer-y := swap_writer_module.o \
- debugfs_writer.o \
- event_filter.o \
- swap_msg.o
-
+++ /dev/null
-/**
- * writer/debugfs_writer.c
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Writer debugfs implementation.
- */
-
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <master/swap_debugfs.h>
-#include <master/swap_initializer.h>
-#include "swap_msg.h"
-#include "event_filter.h"
-
-
-/* ============================================================================
- * === BUFFER ===
- * ============================================================================
- */
-static char *common_buf;
-enum { subbuf_size = 8*1024 };
-enum { common_buf_size = subbuf_size * NR_CPUS };
-
-static int init_buffer(void)
-{
- common_buf = vmalloc(common_buf_size);
-
- return common_buf ? 0 : -ENOMEM;
-}
-
-static void exit_buffer(void)
-{
- vfree(common_buf);
- common_buf = NULL;
-}
-
-static void *get_current_buf(void)
-{
- return common_buf + subbuf_size * get_cpu();
-}
-
-static void put_current_buf(void)
-{
- put_cpu();
-}
-
-
-
-
-
-/* ============================================================================
- * === FOPS_RAW ===
- * ============================================================================
- */
-static ssize_t write_raw(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- int ret;
- void *buf;
-
- if (count > subbuf_size)
- return -EINVAL;
-
- buf = get_current_buf();
- if (copy_from_user(buf, user_buf, count)) {
- ret = -EFAULT;
- goto put_buf;
- }
-
- ret = swap_msg_raw(buf, count);
-
-put_buf:
- put_current_buf();
- return ret;
-}
-
-static const struct file_operations fops_raw = {
- .owner = THIS_MODULE,
- .open = swap_init_simple_open,
- .release = swap_init_simple_release,
- .write = write_raw,
- .llseek = default_llseek
-};
-
-
-
-
-
-/* ============================================================================
- * === FOPS_AVAILABLE_FILTERS ===
- * ============================================================================
- */
-struct read_buf {
- char *begin;
- char *ptr;
- char *end;
-};
-
-static void func_for_read(struct ev_filter *f, void *data)
-{
- struct read_buf *rbuf = (struct read_buf *)data;
- int len = strlen(f->name);
-
- if (rbuf->end - rbuf->ptr < len + 2)
- return;
-
- if (rbuf->ptr != rbuf->begin) {
- *rbuf->ptr = ' ';
- ++rbuf->ptr;
- }
-
- memcpy(rbuf->ptr, f->name, len);
- rbuf->ptr += len;
-}
-
-static ssize_t read_af(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- char buf[512];
- struct read_buf rbuf = {
- .begin = buf,
- .ptr = buf,
- .end = buf + sizeof(buf)
- };
-
- event_filter_on_each(func_for_read, (void *)&rbuf);
-
- *rbuf.ptr = '\n';
- ++rbuf.ptr;
-
- return simple_read_from_buffer(user_buf, count, ppos,
- rbuf.begin, rbuf.ptr - rbuf.begin);
-}
-
-static const struct file_operations fops_available_filters = {
- .owner = THIS_MODULE,
- .open = swap_init_simple_open,
- .release = swap_init_simple_release,
- .read = read_af,
- .llseek = default_llseek
-};
-
-
-
-
-
-/* ============================================================================
- * === FOPS_FILTER ===
- * ============================================================================
- */
-static ssize_t read_filter(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- const char *name = event_filter_get();
- int len = strlen(name);
- char *buf;
- ssize_t ret;
-
- buf = kmalloc(len + 2, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- memcpy(buf, name, len);
- buf[len] = '\0';
- buf[len + 1] = '\n';
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, len + 2);
- kfree(buf);
-
- return ret;
-}
-
-static ssize_t write_filter(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- enum { len = 32 };
- char buf[len], name[len];
- size_t buf_size;
- ssize_t ret;
-
- buf_size = min(count, (size_t)(len - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
-
- buf[len - 1] = '\0';
- ret = sscanf(buf, "%31s", name);
- if (ret != 1)
- return -EINVAL;
-
- ret = event_filter_set(name);
- if (ret)
- return -EINVAL;
-
- return count;
-}
-
-static const struct file_operations fops_filter = {
- .owner = THIS_MODULE,
- .open = swap_init_simple_open,
- .release = swap_init_simple_release,
- .read = read_filter,
- .write = write_filter,
- .llseek = default_llseek
-};
-
-
-
-
-
-/* ============================================================================
- * === INIT/EXIT ===
- * ============================================================================
- */
-static struct dentry *writer_dir;
-
-/**
- * @brief Removes writer debugfs.
- *
- * @return Void.
- */
-void exit_debugfs_writer(void)
-{
- if (writer_dir)
- debugfs_remove_recursive(writer_dir);
-
- writer_dir = NULL;
-
- exit_buffer();
-}
-
-/**
- * @brief Initializes writer debugfs.
- *
- * @return 0 on success, error code on error.
- */
-int init_debugfs_writer(void)
-{
- int ret;
- struct dentry *swap_dir, *dentry;
-
- ret = init_buffer();
- if (ret)
- return ret;
-
- swap_dir = swap_debugfs_getdir();
- if (swap_dir == NULL)
- return -ENOENT;
-
- writer_dir = debugfs_create_dir("writer", swap_dir);
- if (writer_dir == NULL)
- return -ENOMEM;
-
- dentry = debugfs_create_file("raw", 0600, writer_dir, NULL, &fops_raw);
- if (dentry == NULL)
- goto fail;
-
- dentry = debugfs_create_file("available_filters", 0600, writer_dir,
- NULL, &fops_available_filters);
- if (dentry == NULL)
- goto fail;
-
- dentry = debugfs_create_file("filter", 0600,
- writer_dir, NULL, &fops_filter);
- if (dentry == NULL)
- goto fail;
-
- return 0;
-
-fail:
- exit_debugfs_writer();
- return -ENOMEM;
-}
+++ /dev/null
-/**
- * @file writer/debugfs_writer.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Writer debugfs interface declaration.
- */
-
-#ifndef _DEBUGFS_WRITER_H
-#define _DEBUGFS_WRITER_H
-
-int init_debugfs_writer(void);
-void exit_debugfs_writer(void);
-
-#endif /* _DEBUGFS_WRITER_H */
+++ /dev/null
-/**
- * writer/event_filter.c
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Events filter.
- */
-
-
-#include <linux/module.h>
-#include <linux/list.h>
-#include "event_filter.h"
-
-
-static LIST_HEAD(filter_list);
-
-static int func_none(struct task_struct *task)
-{
- return 1;
-}
-
-static struct ev_filter filter_none = {
- .name = "all",
- .filter = func_none
-};
-
-static struct ev_filter *filter_current = &filter_none;
-
-int check_event(struct task_struct *task)
-{
- return filter_current->filter(task);
-}
-EXPORT_SYMBOL_GPL(check_event);
-
-static struct ev_filter *event_filter_find(const char *name)
-{
- struct ev_filter *f, *tmp;
-
- list_for_each_entry_safe(f, tmp, &filter_list, list) {
- if (strcmp(f->name, name) == 0)
- return f;
- }
-
- return NULL;
-}
-
-/**
- * @brief Registers event filter.
- *
- * @param f Pointer to the event filter.
- * @return 0 on success, error code on error.
- */
-int event_filter_register(struct ev_filter *f)
-{
- if (event_filter_find(f->name))
- return -EINVAL;
-
- INIT_LIST_HEAD(&f->list);
- list_add(&f->list, &filter_list);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(event_filter_register);
-
-/**
- * @brief Unregisters event filter.
- *
- * @param f Pointer to the event filter.
- * @return Void.
- */
-void event_filter_unregister(struct ev_filter *f)
-{
- struct ev_filter *filter, *tmp;
-
- if (filter_current == f)
- filter_current = &filter_none;
-
- list_for_each_entry_safe(filter, tmp, &filter_list, list) {
- if (filter == f) {
- list_del(&filter->list);
- break;
- }
- }
-}
-EXPORT_SYMBOL_GPL(event_filter_unregister);
-
-/**
- * @brief Sets event filter by its name.
- *
- * @param name Filter name.
- * @return 0 on success, error code on error.
- */
-int event_filter_set(const char *name)
-{
- struct ev_filter *f;
-
- f = event_filter_find(name);
- if (f == NULL)
- return -EINVAL;
-
- filter_current = f;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(event_filter_set);
-
-/**
- * @brief Gets filter name.
- *
- * @return Pointer to the filter name string.
- */
-const char *event_filter_get(void)
-{
- return filter_current->name;
-}
-
-/**
- * @brief Runs specified callback for each filter in list.
- *
- * @param func Specified callback.
- * @param data Pointer to the data passed to the callback.
- * @return Void.
- */
-void event_filter_on_each(void (*func)(struct ev_filter *, void *),
- void *data)
-{
- struct ev_filter *f, *tmp;
-
- list_for_each_entry_safe(f, tmp, &filter_list, list)
- func(f, data);
-}
-
-/**
- * @brief Initializes event filter.
- *
- * @return Initialization result.
- */
-int event_filter_init(void)
-{
- return event_filter_register(&filter_none);
-}
-
-/**
- * @brief Uninitializes event filter.
- *
- * @return Void.
- */
-void event_filter_exit(void)
-{
- event_filter_unregister(&filter_none);
-}
+++ /dev/null
-/**
- * @file writer/event_filter.h
- * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Event filter interface declaration.
- */
-
-
-#ifndef _EVENT_FILTER_H
-#define _EVENT_FILTER_H
-
-
-#include <linux/list.h>
-
-struct task_struct;
-
-/**
- * @struct ev_filter
- * @bref Event filter structure.
- */
-struct ev_filter {
- struct list_head list; /**< Filter list head. */
- char *name; /**< Filter name. */
- int (*filter)(struct task_struct *); /**< Filter function. */
-};
-
-
-int check_event(struct task_struct *task);
-
-int event_filter_register(struct ev_filter *f);
-void event_filter_unregister(struct ev_filter *f);
-int event_filter_set(const char *name);
-const char *event_filter_get(void);
-
-void event_filter_on_each(void (*func)(struct ev_filter *, void *),
- void *data);
-
-int event_filter_init(void);
-void event_filter_exit(void);
-
-#endif /* _EVENT_FILTER_H */
+++ /dev/null
-/**
- * @file writer/kernel_operations.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Writer kernel operations.
- */
-
-/* Kernel functions wrap */
-
-#ifndef __KERNEL_OPERATIONS_H__
-#define __KERNEL_OPERATIONS_H__
-
-#include <linux/kernel.h>
-#include <linux/uaccess.h>
-#include <asm/ptrace.h>
-
-/* MESSAGES */
-
-/** Prints debug message.*/
-#define print_debug(msg, args...) \
- printk(KERN_DEBUG "SWAP_WRITER DEBUG : " msg, ##args)
-/** Prints info message.*/
-#define print_msg(msg, args...) \
- printk(KERN_INFO "SWAP_WRITER : " msg, ##args)
-/** Prints warning message.*/
-#define print_warn(msg, args...) \
- printk(KERN_WARNING "SWAP_WRITER WARNING : " msg, ##args)
-/** Prints error message.*/
-#define print_err(msg, args...) \
- printk(KERN_ERR "SWAP_WRITER ERROR : " msg, ##args)
-/** Prints critical error message.*/
-#define print_crit(msg, args...) \
- printk(KERN_CRIT "SWAP_WRITER CRITICAL : " msg, ##args)
-
-/* ARCH-DEPENDED OPERATIONS */
-
-
-/* Regs manipulations */
-#if defined(CONFIG_ARM)
-
-#define get_regs_ip(regs) (regs->ARM_pc) /**< Get pc reg. */
-#define get_regs_ret_func(regs) (regs->ARM_lr) /**< Get lr reg. */
-#define get_regs_ret_val(regs) (regs->ARM_r0) /**< Get ret val. */
-#define get_regs_stack_ptr(regs) (regs->ARM_sp) /**< Get stack pointer. */
-
-#elif defined(CONFIG_X86_32)
-
-#define get_regs_ip(regs) (regs->ip - 1) /**< Get ip. */
-#define get_regs_ret_val(regs) (regs->ax) /**< Get ret val. */
-#define get_regs_stack_ptr(regs) (regs->sp) /**< Get stack pointer. */
-
-static inline u32 get_regs_ret_func(struct pt_regs *regs)
-{
- u32 *sp, addr = 0;
-
- if (user_mode(regs)) {
- sp = (u32 *)regs->sp;
- if (get_user(addr, sp))
- printk(KERN_INFO "failed to dereference a pointer, sp=%p, "
- "pc=%lx\n", sp, get_regs_ip(regs));
- } else {
- sp = (u32 *)kernel_stack_pointer(regs);
- addr = *sp;
- }
-
- return addr;
-}
-
-#endif /* CONFIG_arch */
-
-#endif /* __KERNEL_OPERATIONS_H__ */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/ctype.h>
-#include <linux/errno.h>
-#include <linux/atomic.h>
-#include <linux/module.h>
-#include <kprobe/swap_kprobes.h>
-#include <buffer/swap_buffer_module.h>
-#include <swap-asm/swap_kprobes.h>
-#include <swap-asm/swap_uprobes.h>
-#include "swap_msg.h"
-
-
-#define MSG_PREFIX KERN_INFO "[SWAP_MSG] "
-
-
-struct swap_msg {
- u32 msg_id;
- u32 seq_num;
- u64 time;
- u32 len;
- char payload[0];
-} __packed;
-
-
-static char *cpu_buf[NR_CPUS];
-static atomic_t seq_num = ATOMIC_INIT(-1);
-static atomic_t discarded = ATOMIC_INIT(0);
-
-
-int swap_msg_init(void)
-{
- size_t i;
- const size_t end = ((size_t) 0) - 1;
-
- for (i = 0; i < NR_CPUS; ++i) {
- cpu_buf[i] = kmalloc(SWAP_MSG_BUF_SIZE, GFP_KERNEL);
- if (cpu_buf[i] == NULL)
- goto no_mem;
- }
-
- return 0;
-
-no_mem:
- --i;
- for (; i != end; --i)
- kfree(cpu_buf[i]);
-
- return -ENOMEM;
-}
-
-void swap_msg_exit(void)
-{
- int i;
-
- for (i = 0; i < NR_CPUS; ++i)
- kfree(cpu_buf[i]);
-}
-
-void swap_msg_seq_num_reset(void)
-{
- atomic_set(&seq_num, -1);
-}
-EXPORT_SYMBOL_GPL(swap_msg_seq_num_reset);
-
-void swap_msg_discard_reset(void)
-{
- atomic_set(&discarded, 0);
-}
-EXPORT_SYMBOL_GPL(swap_msg_discard_reset);
-
-int swap_msg_discard_get(void)
-{
- return atomic_read(&discarded);
-}
-EXPORT_SYMBOL_GPL(swap_msg_discard_get);
-
-
-u64 swap_msg_timespec2time(struct timespec *ts)
-{
- return ((u64)ts->tv_nsec) << 32 | ts->tv_sec;
-}
-
-
-
-
-
-struct swap_msg *swap_msg_get(enum swap_msg_id id)
-{
- struct swap_msg *m;
-
- m = (struct swap_msg *)cpu_buf[get_cpu()];
-
- m->msg_id = (u32)id;
- m->seq_num = atomic_inc_return(&seq_num);
- m->time = swap_msg_current_time();
-
- return m;
-}
-EXPORT_SYMBOL_GPL(swap_msg_get);
-
-static int __swap_msg_flush(struct swap_msg *m, size_t size, bool wakeup)
-{
- if (unlikely(size >= SWAP_MSG_PAYLOAD_SIZE))
- return -ENOMEM;
-
- m->len = size;
-
- if (swap_buffer_write(m, SWAP_MSG_PRIV_DATA + size, wakeup) !=
- (SWAP_MSG_PRIV_DATA + size)) {
- atomic_inc(&discarded);
- return -EINVAL;
- }
-
- return 0;
-}
-
-int swap_msg_flush(struct swap_msg *m, size_t size)
-{
- return __swap_msg_flush(m, size, true);
-}
-EXPORT_SYMBOL_GPL(swap_msg_flush);
-
-int swap_msg_flush_wakeupoff(struct swap_msg *m, size_t size)
-{
- return __swap_msg_flush(m, size, false);
-}
-EXPORT_SYMBOL_GPL(swap_msg_flush_wakeupoff);
-
-void swap_msg_put(struct swap_msg *m)
-{
- put_cpu();
-}
-EXPORT_SYMBOL_GPL(swap_msg_put);
-
-
-
-
-
-
-static unsigned long get_arg(struct pt_regs *regs, unsigned long n)
-{
- return user_mode(regs) ?
- swap_get_uarg(regs, n) : /* US argument */
- swap_get_sarg(regs, n); /* sys_call argument */
-}
-
-int swap_msg_pack_args(char *buf, int len,
- const char *fmt, struct pt_regs *regs)
-{
- char *buf_old = buf;
- u32 *tmp_u32;
- u64 *tmp_u64;
- int i, /* the index of the argument */
- fmt_i, /* format index */
- fmt_len; /* the number of parameters, in format */
-
- fmt_len = strlen(fmt);
-
- for (i = 0, fmt_i = 0; fmt_i < fmt_len; ++i, ++fmt_i) {
- if (len < 2)
- return -ENOMEM;
-
- *buf = fmt[fmt_i];
- buf += 1;
- len -= 1;
-
- switch (fmt[fmt_i]) {
- case 'b': /* 1 byte(bool) */
- *buf = (char)!!get_arg(regs, i);
- buf += 1;
- len -= 1;
- break;
- case 'c': /* 1 byte(char) */
- *buf = (char)get_arg(regs, i);
- buf += 1;
- len -= 1;
- break;
- case 'f': /* 4 byte(float) */
- case 'd': /* 4 byte(int) */
- if (len < 4)
- return -ENOMEM;
- tmp_u32 = (u32 *)buf;
- *tmp_u32 = (u32)get_arg(regs, i);
- buf += 4;
- len -= 4;
- break;
- case 'x': /* 8 byte(long) */
- case 'p': /* 8 byte(pointer) */
- if (len < 8)
- return -ENOMEM;
- tmp_u64 = (u64 *)buf;
- *tmp_u64 = (u64)get_arg(regs, i);
- buf += 8;
- len -= 8;
- break;
- case 'w': /* 8 byte(double) */
- if (len < 8)
- return -ENOMEM;
- tmp_u64 = (u64 *)buf;
- *tmp_u64 = get_arg(regs, i);
- ++i;
- *tmp_u64 |= (u64)get_arg(regs, i) << 32;
- buf += 8;
- len -= 8;
- break;
- case 's': /* string end with '\0' */
- {
- enum { max_str_len = 512 };
- const char __user *user_s;
- int len_s, ret;
-
- user_s = (const char __user *)get_arg(regs, i);
- len_s = strnlen_user(user_s, max_str_len);
- if (len < len_s)
- return -ENOMEM;
-
- ret = strncpy_from_user(buf, user_s, len_s);
- if (ret < 0)
- return -EFAULT;
-
- buf[ret] = '\0';
-
- buf += ret + 1;
- len -= ret + 1;
- }
- break;
- default:
- return -EINVAL;
- }
- }
-
- return buf - buf_old;
-}
-EXPORT_SYMBOL_GPL(swap_msg_pack_args);
-
-int swap_msg_pack_ret_val(char *buf, int len,
- char ret_type, struct pt_regs *regs)
-{
- const char *buf_old = buf;
- u32 *tmp_u32;
- u64 *tmp_u64;
-
- *buf = ret_type;
- ++buf;
-
- switch (ret_type) {
- case 'b': /* 1 byte(bool) */
- if (len < 1)
- return -ENOMEM;
- *buf = (char)!!regs_return_value(regs);
- ++buf;
- break;
- case 'c': /* 1 byte(char) */
- if (len < 1)
- return -ENOMEM;
- *buf = (char)regs_return_value(regs);
- ++buf;
- break;
- case 'd': /* 4 byte(int) */
- if (len < 4)
- return -ENOMEM;
- tmp_u32 = (u32 *)buf;
- *tmp_u32 = regs_return_value(regs);
- buf += 4;
- break;
- case 'x': /* 8 byte(long) */
- case 'p': /* 8 byte(pointer) */
- if (len < 8)
- return -ENOMEM;
- tmp_u64 = (u64 *)buf;
- *tmp_u64 = (u64)regs_return_value(regs);
- buf += 8;
- break;
- case 's': /* string end with '\0' */
- {
- enum { max_str_len = 512 };
- const char __user *user_s;
- int len_s, ret;
-
- user_s = (const char __user *)regs_return_value(regs);
- len_s = strnlen_user(user_s, max_str_len);
- if (len < len_s)
- return -ENOMEM;
-
- ret = strncpy_from_user(buf, user_s, len_s);
- if (ret < 0)
- return -EFAULT;
-
- buf[ret] = '\0';
- buf += ret + 1;
- }
- break;
- case 'n':
- case 'v':
- break;
- case 'f': /* 4 byte(float) */
- if (len < 4)
- return -ENOMEM;
- tmp_u32 = (u32 *)buf;
- *tmp_u32 = swap_get_urp_float(regs);
- buf += 4;
- break;
- case 'w': /* 8 byte(double) */
- if (len < 8)
- return -ENOMEM;
- tmp_u64 = (u64 *)buf;
- *tmp_u64 = swap_get_urp_double(regs);
- buf += 8;
- break;
- default:
- return -EINVAL;
- }
-
- return buf - buf_old;
-}
-EXPORT_SYMBOL_GPL(swap_msg_pack_ret_val);
-
-
-
-
-
-int swap_msg_raw(void *data, size_t size)
-{
- struct swap_msg *m = (struct swap_msg *)data;
-
- if (sizeof(*m) > size) {
- printk(MSG_PREFIX "ERROR: message RAW small size=%u\n", size);
- return -EINVAL;
- }
-
- if (m->len + sizeof(*m) != size) {
- printk(MSG_PREFIX "ERROR: message RAW wrong format\n");
- return -EINVAL;
- }
-
- m->seq_num = atomic_inc_return(&seq_num);
-
- /* TODO: What should be returned?! When message was discarded. */
- if (swap_buffer_write(m, size, true) != size)
- atomic_inc(&discarded);
-
- return size;
-}
-EXPORT_SYMBOL_GPL(swap_msg_raw);
-
-void swap_msg_error(const char *fmt, ...)
-{
- int ret;
- struct swap_msg *m;
- void *p;
- size_t size;
- va_list args;
-
- m = swap_msg_get(MSG_ERROR);
- p = swap_msg_payload(m);
- size = swap_msg_size(m);
-
- va_start(args, fmt);
- ret = vsnprintf(p, size, fmt, args);
- va_end(args);
-
- if (ret <= 0) {
- printk(MSG_PREFIX "ERROR: msg error packing, ret=%d\n", ret);
- goto put_msg;
- }
-
- swap_msg_flush(m, ret + 1);
-
-put_msg:
- swap_msg_put(m);
-}
-EXPORT_SYMBOL_GPL(swap_msg_error);
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#ifndef _SWAP_MSG_H
-#define _SWAP_MSG_H
-
-
-#include <linux/time.h>
-#include <linux/types.h>
-
-
-enum swap_msg_id {
- MSG_PROC_INFO = 0x0001,
- MSG_TERMINATE = 0x0002,
- MSG_ERROR = 0x0003,
- MSG_SAMPLE = 0x0004,
- MSG_FUNCTION_ENTRY = 0x0008,
- MSG_FUNCTION_EXIT = 0x0009,
- MSG_SYSCALL_ENTRY = 0x000a,
- MSG_SYSCALL_EXIT = 0x000b,
- MSG_FILE_FUNCTION_ENTRY = 0x000c,
- MSG_FILE_FUNCTION_EXIT = 0x000d,
- MSG_PROCESS_STATUS_INFO = 0x000e,
- MSG_CONTEXT_SWITCH_ENTRY = 0x0010,
- MSG_CONTEXT_SWITCH_EXIT = 0x0011,
- MSG_PROC_MAP = 0x0012,
- MSG_PROC_UNMAP = 0x0013,
- MSG_PROC_COMM = 0x0014,
- MSG_WEB_FUNCTION_ENTRY = 0x0015,
- MSG_WEB_FUNCTION_EXIT = 0x0016,
- MSG_NSP = 0x0019,
- MSG_WSP = 0x001a,
- MSG_FBI = 0x0020
-};
-
-enum {
- SWAP_MSG_PRIV_DATA = 20,
- SWAP_MSG_BUF_SIZE = 32 * 1024,
- SWAP_MSG_PAYLOAD_SIZE = SWAP_MSG_BUF_SIZE - SWAP_MSG_PRIV_DATA
-};
-
-
-struct swap_msg;
-
-
-static inline u64 swap_msg_spec2time(struct timespec *ts)
-{
- return ((u64)ts->tv_nsec) << 32 | ts->tv_sec;
-}
-
-static inline u64 swap_msg_current_time(void)
-{
- struct timespec ts;
- getnstimeofday(&ts);
- return swap_msg_spec2time(&ts);
-}
-
-struct swap_msg *swap_msg_get(enum swap_msg_id id);
-int swap_msg_flush(struct swap_msg *m, size_t size);
-int swap_msg_flush_wakeupoff(struct swap_msg *m, size_t size);
-void swap_msg_put(struct swap_msg *m);
-
-static inline void *swap_msg_payload(struct swap_msg *m)
-{
- return (void *)m + SWAP_MSG_PRIV_DATA;
-}
-
-static inline size_t swap_msg_size(struct swap_msg *m)
-{
- return (size_t)SWAP_MSG_PAYLOAD_SIZE;
-}
-
-
-int swap_msg_pack_args(char *buf, int len,
- const char *fmt, struct pt_regs *regs);
-int swap_msg_pack_ret_val(char *buf, int len,
- char ret_type, struct pt_regs *regs);
-
-
-int swap_msg_raw(void *buf, size_t size);
-void swap_msg_error(const char *fmt, ...);
-
-void swap_msg_seq_num_reset(void);
-void swap_msg_discard_reset(void);
-int swap_msg_discard_get(void);
-
-int swap_msg_init(void);
-void swap_msg_exit(void);
-
-
-#endif /* _SWAP_MSG_H */
+++ /dev/null
-/**
- * @file writer/swap_writer_errors.h
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Writer module error codes.
- */
-
-#ifndef __SWAP_WRITER_ERRORS_H__
-#define __SWAP_WRITER_ERRORS_H__
-
-/**
- * @enum _swap_writer_errors
- * Error codes.
- */
-enum _swap_writer_errors {
- E_SW_SUCCESS = 0 /**< Success. */
-};
-
-#endif /* __SWAP_WRITER_ERRORS_H__ */
+++ /dev/null
-/**
- * writer/swap_writer_module.c
- * @author Alexander Aksenov <a.aksenov@samsung.com>
- * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
- * @author Vyacheslav Cherkashin
- *
- * @section LICENSE
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @section COPYRIGHT
- *
- * Copyright (C) Samsung Electronics, 2013
- *
- * @section DESCRIPTION
- *
- * Packing and writing data.
- */
-
-
-#include <linux/module.h>
-#include <master/swap_initializer.h>
-#include "swap_msg.h"
-#include "event_filter.h"
-#include "debugfs_writer.h"
-
-
-static int core_init(void)
-{
- int ret;
-
- ret = swap_msg_init();
- if (ret)
- return ret;
-
- ret = event_filter_init();
- if (ret)
- swap_msg_exit();
-
- return ret;
-}
-
-static void core_exit(void)
-{
- event_filter_exit();
- swap_msg_exit();
-}
-
-SWAP_LIGHT_INIT_MODULE(NULL, core_init, core_exit,
- init_debugfs_writer, exit_debugfs_writer);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP Writer module");
-MODULE_AUTHOR("Cherkashin V., Aksenov A.S.");
+++ /dev/null
-ccflags-y := -Ikernel/swap
-
-ifeq ($(CONFIG_ARM), y)
- link = arm
-endif
-
-ifeq ($(CONFIG_X86), y)
- link = x86
-endif
-
-ccflags-y += -Ikernel/swap/kprobe/arch/$(link) \
- -Ikernel/swap/uprobe/arch/$(link)
-
-obj-$(CONFIG_SWAP_DA) := swap_wsp.o
-swap_wsp-y := wsp_module.o \
- wsp_msg.o \
- wsp_debugfs.o \
- wsp.o \
- wsp_res.o
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <uprobe/swap_uaccess.h>
-#include <us_manager/sspt/sspt.h>
-#include <us_manager/probes/probe_info_new.h>
-#include "wsp.h"
-#include "wsp_res.h"
-#include "wsp_msg.h"
-
-
-struct wsp_probe {
- const char *name;
- struct probe_new probe;
-};
-
-struct wsp_bin {
- const char *name;
- unsigned long cnt;
- struct wsp_probe *probe_array;
-};
-
-
-/* TODO: configure this from outside (using debugfs) */
-static const char webapp_path[] = "/usr/bin/wrt_launchpad_daemon";
-static const char ewebkit_path[] = "/usr/lib/libewebkit2.so";
-
-
-#define WSP_PROBE_MAKE(_name, _info) \
-{ \
- .name = _name, \
- .probe.offset = 0, \
- .probe.info = _info \
-}
-
-
-static void do_res_processing_begin(void *data, void *ptr, enum wsp_res_t type)
-{
- struct wsp_res **save_res = (struct wsp_res **)data;
- struct wsp_res *res;
-
- res = wsp_res_find(ptr, type);
-
- /* save res pointer */
- *save_res = res;
- if (res) {
- wsp_msg(WSP_RES_PROC_BEGIN, res->id, NULL);
- wsp_res_stat_set_next(res, WRS_ADD_DATA);
- }
-}
-
-static void do_res_processing_end(struct wsp_res *res)
-{
- wsp_msg(WSP_RES_PROC_END, res->id, NULL);
-}
-
-static void do_res_finish(struct wsp_res *res)
-{
- wsp_msg(WSP_RES_LOAD_END, res->id, NULL);
- wsp_res_stat_set_next(res, WRS_FINISH);
- wsp_res_del(res);
-}
-
-
-/*
- * soup_req
- */
-static int soup_req_handle(struct kprobe *p, struct pt_regs *regs)
-{
- enum { max_str_len = 512 };
- const char __user *user_s;
- const char *path;
- struct wsp_res *res;
-
- res = wsp_res_last();
- if (res == NULL) {
- pr_err("last wsp_res is not found\n");
- return 0;
- }
-
- user_s = (const char __user *)swap_get_uarg(regs, 1);
- path = strdup_from_user(user_s, GFP_ATOMIC);
- if (path == NULL) {
- pr_warn("soup_req_handle: invalid path\n");
- return 0;
- }
-
- wsp_msg(WSP_RES_LOAD_BEGIN, res->id, path);
- wsp_res_stat_set_next(res, WRS_SOUP_REQ);
- kfree(path);
-
- return 0;
-}
-
-static struct probe_info_new soup_req = MAKE_UPROBE(soup_req_handle);
-
-
-/*
- * main_res_req
- */
-static int mres_req_handle(struct kprobe *p, struct pt_regs *regs)
-{
- void *ptr = (void *)swap_get_uarg(regs, 0);
- struct wsp_res *res;
-
- res = wsp_res_new(ptr, WR_MAIN);
- if (res)
- wsp_res_stat_set_next(res, WRS_WILL_REQ);
-
- return 0;
-}
-
-static struct probe_info_new mres_req = MAKE_UPROBE(mres_req_handle);
-
-
-/*
- * main_res_add_data
- */
-
-static int mres_adata_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- void *ptr = (void *)swap_get_uarg(regs, 0);
-
- do_res_processing_begin(ri->data, ptr, WR_MAIN);
-
- return 0;
-}
-
-static int mres_adata_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- struct wsp_res *res = *(struct wsp_res **)ri->data;
-
- if (res)
- do_res_processing_end(res);
-
- return 0;
-}
-
-static struct probe_info_new mres_adata =
- MAKE_URPROBE(mres_adata_eh, mres_adata_rh,
- sizeof(struct wsp_res *));
-
-
-/*
- * main_res_finish
- */
-static int mres_finish_handle(struct kprobe *p, struct pt_regs *regs)
-{
- void *ptr = (void *)swap_get_uarg(regs, 0);
- struct wsp_res *res;
-
- res = wsp_res_find(ptr, WR_MAIN);
- if (res) {
- wsp_current_set_stat(TDS_FINISH_MAIN_LOAD);
- do_res_finish(res);
- }
-
- return 0;
-}
-
-static struct probe_info_new mres_finish = MAKE_UPROBE(mres_finish_handle);
-
-
-/*
- * res_request
- */
-static int res_request_handle(struct kprobe *p, struct pt_regs *regs)
-{
- void *ptr = (void *)swap_get_uarg(regs, 0);
- struct wsp_res *res;
-
- res = wsp_res_last();
- if (res) {
- if (res->type == WR_MAIN && res->stat == WRS_WILL_REQ)
- /* skip */
- return 0;
- }
-
- res = wsp_res_new(ptr, WR_ANY);
- if (res)
- wsp_res_stat_set_next(res, WRS_WILL_REQ);
-
- return 0;
-}
-
-static struct probe_info_new res_request = MAKE_UPROBE(res_request_handle);
-
-
-/*
- * res_finish
- */
-static int res_finish_ehandle(struct uretprobe_instance *ri,
- struct pt_regs *regs)
-{
- void *ptr = (void *)swap_get_uarg(regs, 0);
-
- do_res_processing_begin(ri->data, ptr, WR_ANY);
-
- return 0;
-}
-
-static int res_finish_rhandle(struct uretprobe_instance *ri,
- struct pt_regs *regs)
-{
- struct wsp_res *res = *(struct wsp_res **)ri->data;
-
- if (res) {
- do_res_processing_end(res);
- do_res_finish(res);
- }
-
- return 0;
-}
-
-static struct probe_info_new res_finish =
- MAKE_URPROBE(res_finish_ehandle, res_finish_rhandle,
- sizeof(struct wsp_res *));
-
-
-/*
- * redraw
- */
-static int redraw_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- enum tdata_stat stat;
-
- stat = wsp_current_get_stat();
-
- if (stat == TDS_FINISH_MAIN_LOAD)
- wsp_msg(WSP_DRAW_BEGIN, 0, NULL);
-
- return 0;
-}
-
-static int redraw_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- if (wsp_current_get_stat() == TDS_FINISH_MAIN_LOAD) {
- wsp_current_set_stat(TDS_DRAW);
- wsp_msg(WSP_DRAW_END, 0, NULL);
- }
-
- return 0;
-}
-
-static struct probe_info_new redraw = MAKE_URPROBE(redraw_eh, redraw_rh, 0);
-
-
-static struct wsp_probe ewebkit_probe_array[] = {
- /* plt */
- /* soup_requester_request@plt */
- WSP_PROBE_MAKE("soup_requester_request@plt", &soup_req),
-
- /* main_res */
- /* WebCore::MainResourceLoader::willSendRequest(WebCore::ResourceRequest&, WebCore::ResourceResponse const&) */
- WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader15willSendRequestERNS_15ResourceRequestERKNS_16ResourceResponseE", &mres_req),
- /* WebCore::MainResourceLoader::addData(char const*, int, bool) */
- WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader7addDataEPKcib", &mres_adata),
- /* WebCore::MainResourceLoader::didFinishLoading(double) */
- WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader16didFinishLoadingEd", &mres_finish),
-
-
- /* res */
- /* WebCore::ResourceLoader::willSendRequest(WebCore::ResourceRequest&, WebCore::ResourceResponse const&) */
- WSP_PROBE_MAKE("_ZN7WebCore14ResourceLoader15willSendRequestERNS_15ResourceRequestERKNS_16ResourceResponseE", &res_request),
- /* WebCore::ResourceLoader::didFinishLoading(WebCore::ResourceHandle*, double) */
- WSP_PROBE_MAKE("_ZN7WebCore14ResourceLoader16didFinishLoadingEPNS_14ResourceHandleEd", &res_finish),
-
-
- /* redraw */
- /* WebKit::LayerTreeCoordinator::flushPendingLayerChanges() */
- WSP_PROBE_MAKE("_ZN6WebKit20LayerTreeCoordinator24flushPendingLayerChangesEv", &redraw),
-};
-
-enum {
- ewebkit_probes_cnt =
- sizeof(ewebkit_probe_array) / sizeof(struct wsp_probe)
-};
-
-static struct wsp_bin ewebkit = {
- .name = ewebkit_path,
- .cnt = ewebkit_probes_cnt,
- .probe_array = ewebkit_probe_array
-};
-
-
-/* check ewebkit_probe_array on init address */
-static bool wsp_is_addr_init(void)
-{
- int i;
-
- for (i = 0; i < ewebkit_probes_cnt; ++i)
- if (ewebkit_probe_array[i].probe.offset == 0)
- return false;
-
- return true;
-}
-
-
-static int wsp_probe_register(struct pf_group *pfg, struct dentry *dentry,
- struct wsp_probe *wsp_probe)
-{
- struct probe_new *probe_new = &wsp_probe->probe;
-
- return pin_register(probe_new, pfg, dentry);
-}
-
-static void wsp_probe_unregister(struct pf_group *pfg, struct dentry *dentry,
- struct wsp_probe *wsp_probe)
-{
- struct probe_new *probe_new = &wsp_probe->probe;
-
- pin_unregister(probe_new, pfg, dentry);
-}
-
-
-
-
-static int wsp_bin_register(struct pf_group *pfg, struct wsp_bin *bin)
-{
- int i, ret;
- struct dentry *dentry;
-
- dentry = dentry_by_path(bin->name);
- if (dentry == NULL) {
- pr_err("dentry not found (path='%s'\n", bin->name);
- return -EINVAL;
- }
-
- for (i = 0; i < bin->cnt; ++i) {
- struct wsp_probe *p = &bin->probe_array[i];
-
- ret = wsp_probe_register(pfg, dentry, p);
- if (ret) {
- pr_err("ERROR: wsp_probe_register, addr=%lx ret=%d\n",
- p->probe.offset, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
-static void wsp_bin_unregister(struct pf_group *pfg, struct wsp_bin *bin)
-{
- int i;
- struct dentry *dentry;
-
- dentry = dentry_by_path(bin->name);
- for (i = 0; i < bin->cnt; ++i)
- wsp_probe_unregister(pfg, dentry, &bin->probe_array[i]);
-}
-
-
-static struct pf_group *g_pfg;
-
-static int wsp_app_register(void)
-{
- struct dentry *dentry;
-
- dentry = dentry_by_path(webapp_path);
- if (dentry == NULL) {
- pr_err("dentry not found (path='%s'\n", webapp_path);
- return -EINVAL;
- }
-
- g_pfg = get_pf_group_by_dentry(dentry, (void *)dentry);
- if (g_pfg == NULL) {
- pr_err("g_pfg is NULL (by dentry=%p)\n", dentry);
- return -ENOMEM;
- }
-
- return wsp_bin_register(g_pfg, &ewebkit);
-}
-
-static void wsp_app_unregister(void)
-{
- wsp_bin_unregister(g_pfg, &ewebkit);
- put_pf_group(g_pfg);
-}
-
-
-static int do_wsp_on(void)
-{
- int ret;
-
- ret = wsp_res_init();
- if (ret)
- return ret;
-
- ret = wsp_app_register();
- if (ret)
- wsp_res_exit();
-
- return ret;
-}
-
-static void do_wsp_off(void)
-{
- wsp_app_unregister();
- wsp_res_exit();
-}
-
-
-static enum wsp_mode g_mode = WSP_OFF;
-static DEFINE_MUTEX(g_mode_mutex);
-
-int wsp_set_addr(const char *name, unsigned long offset)
-{
- int i, ret = 0;
-
- if (mutex_trylock(&g_mode_mutex) == 0)
- return -EBUSY;
-
- for (i = 0; i < ewebkit_probes_cnt; ++i) {
- if (0 == strcmp(name, ewebkit_probe_array[i].name)) {
- ewebkit_probe_array[i].probe.offset = offset;
- goto unlock;
- }
- }
-
- ret = -EINVAL;
-
-unlock:
- mutex_unlock(&g_mode_mutex);
- return ret;
-}
-
-int wsp_set_mode(enum wsp_mode mode)
-{
- int ret = 0;
-
- mutex_lock(&g_mode_mutex);
- switch (mode) {
- case WSP_ON:
- if (g_mode == WSP_ON) {
- ret = -EBUSY;
- goto unlock;
- }
-
- ret = wsp_is_addr_init() ? do_wsp_on() : -EPERM;
- break;
- case WSP_OFF:
- if (g_mode == WSP_OFF) {
- ret = -EBUSY;
- goto unlock;
- }
-
- do_wsp_off();
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
-unlock:
- if (ret == 0)
- g_mode = mode;
-
- mutex_unlock(&g_mode_mutex);
- return ret;
-}
-
-enum wsp_mode wsp_get_mode(void)
-{
- return g_mode;
-}
-
-int wsp_init(void)
-{
- return 0;
-}
-
-void wsp_exit(void)
-{
- wsp_set_mode(WSP_OFF);
-}
+++ /dev/null
-#ifndef _WSP_H
-#define _WSP_H
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-enum wsp_mode {
- WSP_ON,
- WSP_OFF
-};
-
-
-int wsp_set_addr(const char *name, unsigned long offset);
-
-int wsp_set_mode(enum wsp_mode mode);
-enum wsp_mode wsp_get_mode(void);
-
-int wsp_init(void);
-void wsp_exit(void);
-
-
-#endif /* _WSP_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <master/swap_debugfs.h>
-#include "wsp.h"
-
-
-static int do_write_cmd(const char *buf, size_t count)
-{
- int n, ret = 0;
- char *name;
- unsigned long offset;
-
- name = kmalloc(count, GFP_KERNEL);
- if (name == NULL)
- return -ENOMEM;
-
- n = sscanf(buf, "%lx %s", &offset, name);
- if (n != 2) {
- ret = -EINVAL;
- goto free_name;
- }
-
- ret = wsp_set_addr(name, offset);
-
-free_name:
- kfree(name);
- return ret;
-}
-
-/* ============================================================================
- * === DEBUGFS FOR ENABLE ===
- * ============================================================================
- */
-static ssize_t write_cmd(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- enum { max_count = 1024 };
- int ret;
- char *buf;
-
- if (count > max_count)
- return -ENOMEM;
-
- buf = kmalloc(count + 1, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- if (copy_from_user(buf, user_buf, count)) {
- ret = -EFAULT;
- goto free_buf;
- }
-
- buf[count] = '\0';
- ret = do_write_cmd(buf, count);
-
-free_buf:
- kfree(buf);
- return ret ? ret : count;
-}
-
-static const struct file_operations fops_cmd = {
- .write = write_cmd,
- .llseek = default_llseek,
-};
-
-
-
-
-/* ============================================================================
- * === DEBUGFS FOR ENABLE ===
- * ============================================================================
- */
-static ssize_t read_enabled(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- char buf[2];
-
- buf[0] = wsp_get_mode() == WSP_OFF ? '0' : '1';
- buf[1] = '\n';
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
-}
-
-static ssize_t write_enabled(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- int ret = 0;
- char buf[32];
- size_t buf_size;
-
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
-
- buf[buf_size] = '\0';
- switch (buf[0]) {
- case '1':
- ret = wsp_set_mode(WSP_ON);
- break;
- case '0':
- ret = wsp_set_mode(WSP_OFF);
- break;
- default:
- return -EINVAL;
- }
-
- if (ret)
- return ret;
-
- return count;
-}
-
-static const struct file_operations fops_enabled = {
- .read = read_enabled,
- .write = write_enabled,
- .llseek = default_llseek,
-};
-
-
-static struct dentry *wsp_dir;
-
-void wsp_debugfs_exit(void)
-{
- if (wsp_dir)
- debugfs_remove_recursive(wsp_dir);
-
- wsp_dir = NULL;
-}
-
-int wsp_debugfs_init(void)
-{
- struct dentry *dentry;
-
- dentry = swap_debugfs_getdir();
- if (dentry == NULL)
- return -ENOENT;
-
- wsp_dir = debugfs_create_dir("wsp", dentry);
- if (wsp_dir == NULL)
- return -ENOMEM;
-
- dentry = debugfs_create_file("enabled", 0600, wsp_dir, NULL,
- &fops_enabled);
- if (dentry == NULL)
- goto fail;
-
- dentry = debugfs_create_file("cmd", 0600, wsp_dir, NULL, &fops_cmd);
- if (dentry == NULL)
- goto fail;
-
- return 0;
-
-fail:
- wsp_debugfs_exit();
- return -ENOMEM;
-}
+++ /dev/null
-#ifndef _WSP_DEBUGFS_H
-#define _WSP_DEBUGFS_H
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-int wsp_debugfs_init(void);
-void wsp_debugfs_exit(void);
-
-
-#endif /* _WSP_DEBUGFS_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2014
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <master/swap_initializer.h>
-#include "wsp.h"
-#include "wsp_debugfs.h"
-
-
-SWAP_LIGHT_INIT_MODULE(NULL, wsp_init, wsp_exit,
- wsp_debugfs_init, wsp_debugfs_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2016
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <writer/swap_msg.h>
-#include "wsp_msg.h"
-
-
-/*
- * MSG_WSP (payload):
- * +-------------+----------+----------+
- * | name | type | lenght |
- * +-------------+----------+----------+
- * | PID | int | 4 |
- * | wsp_id | int | 4 |
- * | wsp_payload | variable | variable |
- * +-------------+----------+----------+
-
- * wsp_id:
- * - WSP_RES_LOAD_BEGIN = 0x0001
- * - WSP_RES_LOAD_END = 0x0002
- * - WSP_RES_PROC_BEGIN = 0x0003
- * - WSP_RES_PROC_END = 0x0004
- * - WSP_DRAW_BEGIN = 0x0005
- * - WSP_DRAW_END = 0x0006
- *
- * wsp_payload:
- *
- * 1. WSP_RES_LOAD_BEGIN:
- * +--------+--------+----------+
- * | name | type | lenght |
- * +--------+--------+----------+
- * | res_id | int | 4 |
- * | path | string | variable |
- * +--------+--------+----------+
- *
- * 2. WSP_RES_LOAD_END, WSP_RES_PROC_BEGIN, WSP_RES_PROC_END:
- * +--------+--------+----------+
- * | name | type | lenght |
- * +--------+--------+----------+
- * | res_id | int | 4 |
- * +--------+--------+----------+
- *
- * 3. WSP_DRAW_BEGIN, WSP_DRAW_END:
- * no wsp_payload
- */
-
-static int pack_wsp_msg(void *data, size_t size, enum wsp_id id,
- u32 res_id, const char *path)
-{
- size_t len;
- const size_t old_size = size;
-
- /* write PID */
- *(u32 *)data = (u32)current->tgid;
- data += 4;
- size -= 4;
-
- /* write wsp_id */
- *(u32 *)data = (u32)id;
- data += 4;
- size -= 4;
-
- /* pack wsp_payload */
- switch (id) {
- case WSP_RES_LOAD_BEGIN:
- len = strlen(path) + 1;
- if (size < len + 4)
- return -ENOMEM;
-
- /* '+ 4' - skip space for res_id */
- memcpy(data + 4, path, len);
- size -= len;
- case WSP_RES_LOAD_END:
- case WSP_RES_PROC_BEGIN:
- case WSP_RES_PROC_END:
- /* write res_id */
- *(u32 *)data = res_id;
- size -= 4;
- break;
-
- case WSP_DRAW_BEGIN:
- case WSP_DRAW_END:
- break;
-
- default:
- printk(KERN_ERR "unknown wsp_id: id=%u\n", (unsigned)id);
- return -EINVAL;
- }
-
- return old_size - size;
-}
-
-void wsp_msg(enum wsp_id id, u32 res_id, const char *path)
-{
- int ret;
- void *data;
- size_t size;
- struct swap_msg *m;
-
- m = swap_msg_get(MSG_WSP);
- data = swap_msg_payload(m);
- size = swap_msg_size(m);
- ret = pack_wsp_msg(data, size, id, res_id, path);
- if (ret < 0) {
- printk(KERN_ERR "error MSG_WSP packing, ret=%d\n", ret);
- goto put_msg;
- }
-
- swap_msg_flush(m, ret);
-
-put_msg:
- swap_msg_put(m);
-}
+++ /dev/null
-#ifndef _WSP_MSG_H
-#define _WSP_MSG_H
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/types.h>
-
-
-enum wsp_id {
- WSP_RES_LOAD_BEGIN = 0x0001,
- WSP_RES_LOAD_END = 0x0002,
- WSP_RES_PROC_BEGIN = 0x0003,
- WSP_RES_PROC_END = 0x0004,
- WSP_DRAW_BEGIN = 0x0005,
- WSP_DRAW_END = 0x0006
-};
-
-
-void wsp_msg(enum wsp_id id, u32 res_id, const char *path);
-
-
-#endif /* _WSP_MSG_H */
+++ /dev/null
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2016
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/slab.h>
-#include <linux/atomic.h>
-#include <kprobe/swap_kprobes_deps.h>
-#include "wsp_res.h"
-
-static atomic_t wsp_res_count;
-
-static int wsp_tdata_get_id(void)
-{
- return atomic_inc_return(&wsp_res_count);
-}
-
-static struct wsp_tdata *g_tdata;
-
-/* FIXME: get_tdata() need receive for each processes */
-static struct wsp_tdata *get_tdata(void)
-{
- return g_tdata;
-}
-
-
-
-
-
-/* ============================================================================
- * = wsp_tdata =
- * ============================================================================
- */
-struct wsp_tdata {
- struct list_head res_list;
- spinlock_t lock;
-
- enum tdata_stat stat;
-};
-
-static struct wsp_res *wsp_tdata_new_res(struct wsp_tdata *d, void *ptr,
- enum wsp_res_t type)
-{
- struct wsp_res *res;
-
- res = kmalloc(sizeof(*res), GFP_ATOMIC);
- if (res) {
- INIT_LIST_HEAD(&res->list);
- res->ptr = ptr;
- res->id = wsp_tdata_get_id();
- res->type = type;
- res->stat = WRS_NEW;
-
- /* add to list */
- spin_lock(&d->lock);
- list_add(&res->list, &d->res_list);
- spin_unlock(&d->lock);
- }
-
- return res;
-}
-
-static void wsp_tdata_del_res(struct wsp_res *res)
-{
- list_del(&res->list);
- kfree(res);
-}
-
-static struct wsp_tdata *wsp_tdata_create(void)
-{
- struct wsp_tdata *d;
-
- d = kmalloc(sizeof(*d), GFP_ATOMIC);
- if (d) {
- INIT_LIST_HEAD(&d->res_list);
- spin_lock_init(&d->lock);
- d->stat = TDS_NEW;
- }
-
- return d;
-}
-
-static void wsp_tdata_destroy(struct wsp_tdata *d)
-{
- struct wsp_res *res, *n;
-
- spin_lock(&d->lock);
- list_for_each_entry_safe(res, n, &d->res_list, list)
- wsp_tdata_del_res(res);
- spin_unlock(&d->lock);
-
- kfree(d);
-}
-
-static struct wsp_res *wsp_tdata_last_res(struct wsp_tdata *d)
-{
- struct wsp_res *res;
-
- spin_lock(&d->lock);
- res = list_first_entry_or_null(&d->res_list, struct wsp_res, list);
- spin_unlock(&d->lock);
-
- return res;
-}
-
-struct wsp_res *wsp_tdata_find_res(struct wsp_tdata *data, void *ptr,
- enum wsp_res_t type)
-{
- struct wsp_res *res;
-
- list_for_each_entry(res, &data->res_list, list) {
- if (res->type != type)
- continue;
-
- if (res->ptr == ptr) {
- if (res->stat == WRS_ERR) {
- pr_err("ERR: something went wrong\n");
- return NULL;
- }
-
- return res;
- }
- }
-
- return NULL;
-}
-
-
-
-
-
-/* ============================================================================
- * = wsp_current_[get/set]_stat() =
- * ============================================================================
- */
-enum tdata_stat wsp_current_get_stat(void)
-{
- struct wsp_tdata *d;
-
- d = get_tdata();
- if (d)
- return d->stat;
- else
- pr_err("ERR: no current tdata\n");
-
- return TDS_ERR;
-}
-
-void wsp_current_set_stat(enum tdata_stat stat)
-{
- struct wsp_tdata *d;
-
- d = get_tdata();
- if (d)
- d->stat = stat;
- else
- pr_err("ERR: no current tdata\n");
-}
-
-
-
-
-
-/* ============================================================================
- * = wsp_res =
- * ============================================================================
- */
-struct wsp_res *wsp_res_new(void *ptr, enum wsp_res_t type)
-{
- struct wsp_tdata *data;
-
- data = get_tdata();
- if (data == NULL) {
- pr_err("ERR: no current tdata\n");
- return NULL;
- }
-
-
- return wsp_tdata_new_res(data, ptr, type);
-}
-
-void wsp_res_del(struct wsp_res *res)
-{
- wsp_tdata_del_res(res);
-}
-
-struct wsp_res *wsp_res_find(void *ptr, enum wsp_res_t type)
-{
- struct wsp_tdata *data;
-
- data = get_tdata();
- if (data == NULL) {
- pr_err("ERR: no current tdata\n");
- return NULL;
- }
-
- return wsp_tdata_find_res(data, ptr, type);
-}
-
-struct wsp_res *wsp_res_last(void)
-{
- struct wsp_tdata *d;
-
- d = get_tdata();
- if (d == NULL) {
- pr_err("ERR: no current tdata\n");
- return NULL;
- }
-
- return wsp_tdata_last_res(d);
-}
-
-int wsp_res_stat_set_next(struct wsp_res *res, enum wsp_res_stat stat)
-{
- switch (res->stat) {
- case WRS_NEW:
- if (stat == WRS_WILL_REQ) {
- res->stat = stat;
- return 0;
- }
- break;
-
- case WRS_WILL_REQ:
- if (stat == WRS_SOUP_REQ) {
- res->stat = stat;
- return 0;
- }
- break;
-
- case WRS_SOUP_REQ:
- case WRS_ADD_DATA:
- if (stat == WRS_ADD_DATA || stat == WRS_FINISH) {
- res->stat = stat;
- return 0;
- }
- break;
-
- default:
- break;
- }
-
- pr_err("ERR: set_next_stat from %d to %d [id=%d]\n",
- res->stat, stat, res->id);
-
- res->stat = WRS_ERR;
-
- return -1;
-}
-
-
-
-
-
-/* ============================================================================
- * = init/exit() =
- * ============================================================================
- */
-int wsp_res_init(void)
-{
- g_tdata = wsp_tdata_create();
- if (g_tdata == NULL)
- return -ENOMEM;
-
- atomic_set(&wsp_res_count, 0);
-
- return 0;
-}
-
-void wsp_res_exit(void)
-{
- wsp_tdata_destroy(g_tdata);
- g_tdata = NULL;
-}
+++ /dev/null
-#ifndef _WSP_TDATA_H
-#define _WSP_TDATA_H
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) Samsung Electronics, 2015
- *
- * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
- *
- */
-
-
-#include <linux/types.h>
-
-
-enum tdata_stat {
- TDS_ERR,
- TDS_NEW,
- TDS_FINISH_MAIN_LOAD,
- TDS_DRAW
-};
-
-enum wsp_res_t {
- WR_NONE,
- WR_MAIN,
- WR_ANY
-};
-
-enum wsp_res_stat {
- WRS_NEW,
- WRS_WILL_REQ,
- WRS_SOUP_REQ,
- WRS_ADD_DATA,
- WRS_FINISH,
- WRS_ERR
-};
-
-struct wsp_res {
- struct list_head list;
- void *ptr;
- int id;
- enum wsp_res_t type;
- enum wsp_res_stat stat;
-};
-
-
-enum tdata_stat wsp_current_get_stat(void);
-void wsp_current_set_stat(enum tdata_stat stat);
-
-struct wsp_res *wsp_res_new(void *ptr, enum wsp_res_t type);
-void wsp_res_del(struct wsp_res *res);
-
-struct wsp_res *wsp_res_last(void);
-struct wsp_res *wsp_res_find(void *ptr, enum wsp_res_t type);
-
-int wsp_res_stat_set_next(struct wsp_res *res, enum wsp_res_stat stat);
-
-int wsp_res_init(void);
-void wsp_res_exit(void);
-
-
-#endif /* _WSP_TDATA_H */