summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Google) <rostedt@goodmis.org>2022-01-19 22:16:58 -0500
committerSteven Rostedt (Google) <rostedt@goodmis.org>2022-01-27 20:59:30 -0500
commit907cbf7c474bf7fa9d9bedf1e8110f400250e140 (patch)
tree2d5cca64d016b53f9e1069690ecd1d5c8f107995
downloadktrace-907cbf7c474bf7fa9d9bedf1e8110f400250e140.tar.gz
ktrace: Initial commit
Initial commit of the shell like utility to access Linux tracing. Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-rw-r--r--.gitignore3
-rw-r--r--LICENSE359
-rw-r--r--Makefile272
-rw-r--r--scripts/utils.mk226
-rw-r--r--src/.gitignore1
-rw-r--r--src/Makefile37
-rw-r--r--src/create.c399
-rw-r--r--src/ktrace.c66
-rw-r--r--src/ktrace.h21
9 files changed, 1384 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..878caad
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.d
+*~
+*.o
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ff0812f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,359 @@
+Valid-License-Identifier: GPL-2.0
+Valid-License-Identifier: GPL-2.0-only
+Valid-License-Identifier: GPL-2.0+
+Valid-License-Identifier: GPL-2.0-or-later
+SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
+Usage-Guide:
+ To use this license in source code, put one of the following SPDX
+ tag/value pairs into a comment according to the placement
+ guidelines in the licensing rules documentation.
+ For 'GNU General Public License (GPL) version 2 only' use:
+ SPDX-License-Identifier: GPL-2.0
+ or
+ SPDX-License-Identifier: GPL-2.0-only
+ For 'GNU General Public License (GPL) version 2 or any later version' use:
+ SPDX-License-Identifier: GPL-2.0+
+ or
+ SPDX-License-Identifier: GPL-2.0-or-later
+License-Text:
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, 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 Library 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 St, 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 Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..b188ff9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,272 @@
+# SPDX-License-Identifier: LGPL-2.1
+# ktrace version:
+KT_VERSION = 0
+KT_PATCHLEVEL = 0
+KT_EXTRAVERSION = dev
+KTRACE_VERSION = $(KT_VERSION).$(KT_PATCHLEVEL).$(KT_EXTRAVERSION)
+
+export KT_VERSION
+export KT_PATCHLEVEL
+export KT_EXTRAVERSION
+export KTRACE_VERSION
+
+MAKEFLAGS += --no-print-directory
+
+# Makefiles suck: This macro sets a default value of $(2) for the
+# variable named by $(1), unless the variable has been set by
+# environment or command line. This is necessary for CC and AR
+# because make sets default values, so the simpler ?= approach
+# won't work as expected.
+define allow-override
+ $(if $(or $(findstring environment,$(origin $(1))),\
+ $(findstring command line,$(origin $(1)))),,\
+ $(eval $(1) = $(2)))
+endef
+
+# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+$(call allow-override,PKG_CONFIG,pkg-config)
+$(call allow-override,LD_SO_CONF_PATH,/etc/ld.so.conf.d/)
+$(call allow-override,LDCONFIG,ldconfig)
+
+EXT = -std=gnu99
+INSTALL = install
+
+# Use DESTDIR for installing into a different root directory.
+# This is useful for building a package. The program will be
+# installed in this directory as if it was the root directory.
+# Then the build tool can move it later.
+DESTDIR ?=
+DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
+
+LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
+ifeq ($(LP64), 1)
+ libdir_relative_temp = lib64
+else
+ libdir_relative_temp = lib
+endif
+
+libdir_relative ?= $(libdir_relative_temp)
+prefix ?= /usr/local
+man_dir = $(prefix)/share/man
+man_dir_SQ = '$(subst ','\'',$(man_dir))'
+libdir = $(prefix)/$(libdir_relative)
+libdir_SQ = '$(subst ','\'',$(libdir))'
+includedir_relative ?= include
+includedir = $(prefix)/$(includedir_relative)
+includedir_SQ = '$(subst ','\'',$(includedir))'
+pkgconfig_dir ?= $(word 1,$(shell $(PKG_CONFIG) \
+ --variable pc_path pkg-config | tr ":" " "))
+
+
+etcdir ?= /etc
+etcdir_SQ = '$(subst ','\'',$(etcdir))'
+
+export man_dir man_dir_SQ html_install html_install_SQ INSTALL
+export img_install img_install_SQ
+export DESTDIR DESTDIR_SQ
+
+pound := \#
+
+HELP_DIR = -DHELP_DIR=$(html_install)
+HELP_DIR_SQ = '$(subst ','\'',$(HELP_DIR))'
+#' emacs highlighting gets confused by the above escaped quote.
+
+BASH_COMPLETE_DIR ?= $(etcdir)/bash_completion.d
+
+# copy a bit from Linux kbuild
+
+ifeq ("$(origin V)", "command line")
+ VERBOSE = $(V)
+endif
+ifndef VERBOSE
+ VERBOSE = 0
+endif
+
+SILENT := $(if $(findstring s,$(filter-out --%,$(MAKEFLAGS))),1)
+
+LIBTRACEFS_MIN_VERSION = 1.2
+LIBCCLI_MIN_VERSION = 1.1
+
+# Test for necessary libraries
+TEST_LIBTRACEFS = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEFS_MIN_VERSION) libtracefs > /dev/null 2>&1 && echo y")
+
+ifeq ("$(TEST_LIBTRACEFS)", "y")
+LIBTRACEFS_INCLUDES = $(shell sh -c "$(PKG_CONFIG) --cflags libtracefs")
+LIBTRACEFS_LIBS = $(shell sh -c "$(PKG_CONFIG) --libs libtracefs")
+else
+ ifneq ($(MAKECMDGOALS),clean)
+ $(error libtracefs.so minimum version of $(LIBTRACEFS_MIN_VERSION) not installed)
+ endif
+endif
+
+# Test for necessary libraries
+TEST_LIBCCLI = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBCCLI_MIN_VERSION) libccli > /dev/null 2>&1 && echo y")
+
+ifeq ("$(TEST_LIBCCLI)", "y")
+LIBCCLI_INCLUDES = $(shell sh -c "$(PKG_CONFIG) --cflags libccli")
+LIBCCLI_LIBS = $(shell sh -c "$(PKG_CONFIG) --libs libccli")
+else
+ ifneq ($(MAKECMDGOALS),clean)
+ $(error libccli.so minimum version of $(LIBCCLI_MIN_VERSION) not installed)
+ endif
+endif
+
+# $(call test-build, snippet, ret) -> ret if snippet compiles
+# -> empty otherwise
+test-build = $(if $(shell sh -c 'echo "$(1)" | \
+ $(CC) -o /dev/null -c -x c - > /dev/null 2>&1 && echo y'), $2)
+
+ifeq ("$(origin O)", "command line")
+
+ saved-output := $(O)
+ BUILD_OUTPUT := $(shell cd $(O) && /bin/pwd)
+ $(if $(BUILD_OUTPUT),, \
+ $(error output directory "$(saved-output)" does not exist))
+
+else
+ BUILD_OUTPUT = $(CURDIR)
+endif
+
+srctree := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
+objtree := $(BUILD_OUTPUT)
+src := $(srctree)
+obj := $(objtree)
+bdir := $(obj)/src
+
+export prefix src obj bdir
+
+LIBS =$(LIBCCLI_LIBS) $(LIBTRACEFS_LIBS)
+
+export LIBS
+
+export Q SILENT VERBOSE EXT
+
+# Include the utils
+include scripts/utils.mk
+
+# Set compile option CFLAGS if not set elsewhere
+CFLAGS ?= -g -Wall
+CPPFLAGS ?=
+LDFLAGS ?=
+
+CFLAGS += $(LIBCCLI_INCLUDES) $(LIBTRACEFS_INCLUDES)
+
+export CFLAGS
+export INCLUDES
+
+# Append required CFLAGS
+override CFLAGS += -D_GNU_SOURCE $(INCLUDES)
+
+all: all_cmd
+
+TARGETS = ktrace
+
+all_cmd: $(TARGETS)
+
+ktrace: force
+ make -C src $@
+
+VERSION_FILE = ktest_version.h
+
+VIM_TAGS = $(obj)/tags
+EMACS_TAGS = $(obj)/TAGS
+CSCOPE_TAGS = $(obj)/cscope
+
+$(VIM_TAGS): force
+ $(RM) $@
+ $(call find_tag_files) | (cd $(obj) && xargs ctags --extra=+f --c-kinds=+px)
+
+$(EMACS_TAGS): force
+ $(RM) $@
+ $(call find_tag_files) | (cd $(obj) && xargs etags)
+
+$(CSCOPE_TAGS): force
+ $(RM) $(obj)/cscope*
+ $(call find_tag_files) | cscope -b -q
+
+tags: $(VIM_TAGS)
+TAGS: $(EMACS_TAGS)
+cscope: $(CSCOPE_TAGS)
+
+install:
+
+doc:
+ $(Q)$(call descend,$(src)/Documentation,all)
+
+doc_clean:
+ $(Q)$(call descend,$(src)/Documentation,clean)
+
+install_doc:
+ $(Q)$(call descend,$(src)/Documentation,install)
+
+define build_uninstall_script
+ $(Q)mkdir $(BUILD_OUTPUT)/tmp_build
+ $(Q)$(MAKE) -C $(src) DESTDIR=$(BUILD_OUTPUT)/tmp_build/ O=$(BUILD_OUTPUT) $1 > /dev/null
+ $(Q)find $(BUILD_OUTPUT)/tmp_build ! -type d -printf "%P\n" > $(BUILD_OUTPUT)/build_$2
+ $(Q)$(RM) -rf $(BUILD_OUTPUT)/tmp_build
+endef
+
+build_uninstall: $(BUILD_PREFIX)
+ $(call build_uninstall_script,install,uninstall)
+
+$(BUILD_OUTPUT)/build_uninstall: build_uninstall
+
+define uninstall_file
+ if [ -f $(DESTDIR)/$1 -o -h $(DESTDIR)/$1 ]; then \
+ $(call print_uninstall,$(DESTDIR)/$1)$(RM) $(DESTDIR)/$1; \
+ fi;
+endef
+
+uninstall: $(BUILD_OUTPUT)/build_uninstall
+ @$(foreach file,$(shell cat $(BUILD_OUTPUT)/build_uninstall),$(call uninstall_file,$(file)))
+
+PHONY += force
+force:
+
+# Declare the contents of the .PHONY variable as phony. We keep that
+# information in a variable so we can use it in if_changed and friends.
+.PHONY: $(PHONY)
+
+OBJS := $(OBJS:%.o=$(bdir)/%.o)
+DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d)
+
+all: $(DEFAULT_TARGET)
+
+$(bdir):
+ @mkdir -p $(bdir)
+
+VERSION = $(KT_VERSION)
+PATCHLEVEL = $(KT_PATCHLEVEL)
+EXTRAVERSION = $(KT_EXTRAVERSION)
+
+define make_version.h
+ (echo '/* This file is automatically generated. Do not modify. */'; \
+ echo \#define VERSION_CODE $(shell \
+ expr $(VERSION) \* 256 + $(PATCHLEVEL)); \
+ echo '#define EXTRAVERSION ' $(EXTRAVERSION); \
+ echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \
+ ) > $1
+endef
+
+define update_version.h
+ ($(call make_version.h, $@.tmp); \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+ rm -f $@.tmp; \
+ else \
+ echo ' UPDATE $@'; \
+ mv -f $@.tmp $@; \
+ fi);
+endef
+
+$(VERSION_FILE): force
+ $(Q)$(call update_version.h)
+
+clean:
+ $(Q)$(call descend_clean,src)
+ $(Q)$(call do_clean, \
+ $(TARGETS) $(bdir)/*.a $(bdir)/*.so $(bdir)/*.so.* $(bdir)/*.o $(bdir)/.*.d \
+ $(VERSION_FILE))
+
+.PHONY: clean
diff --git a/scripts/utils.mk b/scripts/utils.mk
new file mode 100644
index 0000000..af21322
--- /dev/null
+++ b/scripts/utils.mk
@@ -0,0 +1,226 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Utils
+
+PWD := $(shell /bin/pwd)
+GOBJ = $(notdir $(strip $@))
+BASE1 = $(notdir $(strip $1))
+BASE2 = $(notdir $(strip $2))
+BASEPWD = $(notdir $(strip $(PWD)))
+
+ifeq ($(VERBOSE),1)
+ Q =
+ S =
+else
+ Q = @
+ S = -s
+endif
+
+# Use empty print_* macros if either SILENT or VERBOSE.
+ifeq ($(findstring 1,$(SILENT)$(VERBOSE)),1)
+ print_compile =
+ print_app_build =
+ print_fpic_compile =
+ print_shared_lib_compile =
+ print_plugin_obj_compile =
+ print_plugin_build =
+ print_install =
+ print_uninstall =
+ print_update =
+ print_descend =
+ print_clean =
+ print_asciidoc =
+ print_xsltproc =
+ print_install =
+ hide_xsltproc_output =
+else
+ print_compile = echo ' COMPILE '$(GOBJ);
+ print_app_build = echo ' BUILD '$(GOBJ);
+ print_fpic_compile = echo ' COMPILE FPIC '$(GOBJ);
+ print_shared_lib_compile = echo ' COMPILE SHARED LIB '$(GOBJ);
+ print_plugin_obj_compile = echo ' COMPILE PLUGIN OBJ '$(GOBJ);
+ print_plugin_build = echo ' BUILD PLUGIN '$(GOBJ);
+ print_static_lib_build = echo ' BUILD STATIC LIB '$(GOBJ);
+ print_install = echo ' INSTALL '$(GSPACE)$1' to $(DESTDIR_SQ)$2';
+ print_update = echo ' UPDATE '$(GOBJ);
+ print_descend = echo ' DESCEND '$(BASE1) $(BASE2);
+ print_clean = echo ' CLEAN '$(BASEPWD);
+ print_uninstall = echo ' UNINSTALLING $(DESTDIR_SQ)$1';
+ print_asciidoc = echo ' ASCIIDOC '`basename $@`;
+ print_xsltproc = echo ' XSLTPROC '`basename $@`;
+ print_install = echo ' INSTALL '`basename $1`' to $(DESTDIR_SQ)'$2;
+ hide_xsltproc_output = 2> /dev/null
+endif
+
+do_fpic_compile = \
+ ($(print_fpic_compile) \
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $(EXT) -fPIC $< -o $@)
+
+do_compile = \
+ ($(if $(GENERATE_PIC), $(do_fpic_compile), \
+ $(print_compile) \
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $(EXT) $< -o $@))
+
+do_app_build = \
+ ($(print_app_build) \
+ $(CC) $^ -rdynamic -Wl,-rpath=$(libdir) -o $@ $(LDFLAGS) $(CONFIG_LIBS) $(LIBS))
+
+do_build_static_lib = \
+ ($(print_static_lib_build) \
+ $(RM) $@; $(AR) rcs $@ $^)
+
+do_compile_shared_library = \
+ ($(print_shared_lib_compile) \
+ $(CC) --shared $^ '-Wl,-soname,$(@F),-rpath=$$ORIGIN' -o $@ $(LDFLAGS) $(LIBS))
+
+do_compile_plugin_obj = \
+ ($(print_plugin_obj_compile) \
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) -fPIC -o $@ $<)
+
+do_plugin_build = \
+ ($(print_plugin_build) \
+ $(CC) $(CFLAGS) $(LDFLAGS) -shared -nostartfiles -o $@ $<)
+
+do_clean = \
+ ($(print_clean) \
+ $(RM) $1)
+
+do_compile_python_plugin_obj = \
+ ($(print_plugin_obj_compile) \
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PYTHON_DIR_SQ) $(PYTHON_INCLUDES) -fPIC -o $@ $<)
+
+do_python_plugin_build = \
+ ($(print_plugin_build) \
+ $(CC) $< -shared $(LDFLAGS) $(PYTHON_LDFLAGS) -o $@)
+
+define make_version.h
+ (echo '/* This file is automatically generated. Do not modify. */'; \
+ echo \#define VERSION_CODE $(shell \
+ expr $(VERSION) \* 256 + $(PATCHLEVEL)); \
+ echo '#define EXTRAVERSION ' $(EXTRAVERSION); \
+ echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \
+ echo '#define FILE_VERSION '$(FILE_VERSION); \
+ if [ -d $(src)/.git ]; then \
+ d=`git diff`; \
+ x=""; \
+ if [ ! -z "$$d" ]; then x="+"; fi; \
+ echo '#define VERSION_GIT "'$(shell \
+ git log -1 --pretty=format:"%H" 2>/dev/null)$$x'"'; \
+ else \
+ echo '#define VERSION_GIT "not-a-git-repo"'; \
+ fi \
+ ) > $1
+endef
+
+define update_version.h
+ ($(call make_version.h, $@.tmp); \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+ rm -f $@.tmp; \
+ else \
+ $(print_update) \
+ mv -f $@.tmp $@; \
+ fi);
+endef
+
+define update_dir
+ (echo $1 > $@.tmp; \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+ rm -f $@.tmp; \
+ else \
+ $(print_update) \
+ mv -f $@.tmp $@; \
+ fi);
+endef
+
+define build_prefix
+ (echo $1 > $@.tmp; \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+ rm -f $@.tmp; \
+ else \
+ $(print_update) \
+ mv -f $@.tmp $@; \
+ fi);
+endef
+
+define do_install
+ $(print_install) \
+ if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
+ fi; \
+ $(INSTALL) $(if $3,-m $3,) $1 '$(DESTDIR_SQ)$2'
+endef
+
+define do_install_data
+ $(print_install) \
+ if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
+ fi; \
+ $(INSTALL) -m 644 $1 '$(DESTDIR_SQ)$2'
+endef
+
+#
+# Define a callable command for descending to a new directory
+#
+# Call by doing: $(call descend,directory[,target])
+#
+descend = \
+ ($(print_descend) \
+ mkdir -p $(obj)/$(BASE1); \
+ $(MAKE) $(PRINT_DIR) bdir=$(obj)/$(BASE1) -C $(1) $(2))
+
+descend_clean = \
+ $(MAKE) $(PRINT_DIR) bdir=$(obj)/$(BASE1) -C $(1) clean
+
+define do_install_pkgconfig_file
+ if [ -n "${pkgconfig_dir}" ]; then \
+ $(call do_install,$(PKG_CONFIG_FILE),$(pkgconfig_dir),644); \
+ else \
+ (echo Failed to locate pkg-config directory) 1>&2; \
+ fi
+endef
+
+define do_make_pkgconfig_file
+ $(print_app_build)
+ $(Q)cp -f $(srctree)/${PKG_CONFIG_SOURCE_FILE}.template ${PKG_CONFIG_FILE}; \
+ sed -i "s|INSTALL_PREFIX|${1}|g" ${PKG_CONFIG_FILE}; \
+ sed -i "s|LIB_VERSION|${LIBTRACECMD_VERSION}|g" ${PKG_CONFIG_FILE}; \
+ sed -i "s|LIB_DIR|$(libdir)|g" ${PKG_CONFIG_FILE}; \
+ sed -i "s|LIBTRACEFS_MIN_VERSION|$(LIBTRACEFS_MIN_VERSION)|g" ${PKG_CONFIG_FILE}; \
+ sed -i "s|HEADER_DIR|$(includedir)/trace-cmd|g" ${PKG_CONFIG_FILE};
+endef
+
+do_asciidoc_build = \
+ ($(print_asciidoc) \
+ asciidoc -d manpage -b docbook -o $@ $<)
+
+do_xsltproc_build = \
+ ($(print_xsltproc) \
+ xsltproc --nonet -o $@ ${MANPAGE_DOCBOOK_XSL} $< $(hide_xsltproc_output))
+
+#
+# asciidoc requires a synopsis, but file format man pages (5) do
+# not require them. This removes it from the file in the final step.
+define remove_synopsis
+ (sed -e '/^\.SH "SYNOPSIS"/,/ignore/d' $1 > $1.tmp;\
+ mv $1.tmp $1)
+endef
+
+define do_install_docs
+ $(print_install) \
+ if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
+ fi; \
+ $(INSTALL) -m 644 $1 '$(DESTDIR_SQ)$2'
+endef
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifneq ($(V),1)
+ QUIET_ASCIIDOC = @echo ' ASCIIDOC '$@;
+ QUIET_XMLTO = @echo ' XMLTO '$@;
+ QUIET_SUBDIR0 = +@subdir=
+ QUIET_SUBDIR1 = ;$(NO_SUBDIR) \
+ echo ' SUBDIR ' $$subdir; \
+ $(MAKE) $(PRINT_DIR) -C $$subdir
+ export V
+endif
+endif
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..a828635
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1 @@
+ktrace
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..51c7de8
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: LGPL-2.1
+
+include $(src)/scripts/utils.mk
+
+OBJS =
+OBJS += ktrace.o
+OBJS += create.o
+
+OBJS := $(OBJS:%.o=$(bdir)/%.o)
+DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d)
+
+$(bdir)/%.o: %.c
+ $(Q)$(call do_compile)
+
+$(DEPS): $(bdir)/.%.d: %.c
+ $(Q)$(CC) -M -MT $(bdir)/$*.o $(CPPFLAGS) $(CFLAGS) $< > $@
+
+$(OBJS): $(bdir)/%.o : $(bdir)/.%.d
+
+$(OBJS): | $(bdir)
+$(DEPS): | $(bdir)
+
+$(bdir)/ktrace: $(OBJS)
+ $(Q)$(do_app_build)
+
+ktrace: $(bdir)/ktrace
+
+clean:
+ $(Q)$(call do_clean,$(OBJS) .*.d)
+
+dep_includes := $(wildcard $(DEPS))
+
+ifneq ($(dep_includes),)
+ include $(dep_includes)
+endif
+
+.PHONY: ktrace clean
diff --git a/src/create.c b/src/create.c
new file mode 100644
index 0000000..ce0753c
--- /dev/null
+++ b/src/create.c
@@ -0,0 +1,399 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Google Inc, Steven Rostedt <rostedt@goodmis.org>
+ */
+#include "ktrace.h"
+
+
+static void create_usage(struct ccli *ccli)
+{
+ ccli_printf(ccli, "usage: create <type> <type-command>\n"
+ " <type> : kprobe, eprobe, synthetic_event\n");
+}
+
+static int create_kprobe(struct ccli *ccli, void *data,
+ int argc, char **argv)
+{
+ return 0;
+}
+
+static int add_event_var(struct ccli *ccli, struct tep_handle *tep,
+ char **command, struct tep_event *event,
+ char *line)
+{
+ struct tep_format_field *field;
+ long long offset;
+ bool neg;
+ char *fname;
+ char *type;
+ char *var;
+ char *tmp;
+ char *end;
+ char *p;
+ char ch;
+ int ret;
+
+ p = strchr(line, '=');
+ if (!p) {
+ ccli_printf(ccli, "Invalid variable '%s'\n", line);
+ return -1;
+ }
+
+ *p = '\0';
+ fname = p + 1;
+ for (p++; *p; p++) {
+ if (*p == '.' || *p == '-')
+ break;
+ }
+ ch = *p;
+ *p = '\0';
+
+ field = tep_find_any_field(event, fname);
+ if (!field) {
+ ccli_printf(ccli, "# Cannot find field '%s' for event '%s'\n",
+ fname, event->name);
+ return -1;
+ }
+
+ ret = asprintf(&var, "$%s", fname);
+ if (ret < 0)
+ return -1;
+
+ *p = ch;
+ for (; *p; p++) {
+ switch(*p) {
+ case '.':
+ p++;
+ type = p;
+ for (; *p; p++) {
+ if (*p == '.' || *p == '-')
+ break;
+ }
+ if (*p == '.') {
+ ccli_printf(ccli, "# Two types can not be togethe '%s'\n",
+ line);
+ goto out;
+ }
+ if (strncmp(type, "string", 6) == 0 ||
+ strncmp(type, "ustring", 7) == 0) {
+ if (*p) {
+ ccli_printf(ccli, "# Strings can not be deferenced '%s'\n",
+ type);
+ goto out;
+ }
+ ret = asprintf(&tmp, "+0(%s):%.*s",
+ var, (int)(p - type),
+ type);
+ } else {
+ ret = asprintf(&tmp, "%s:%.*s",
+ var, (int)(p - type),
+ type);
+ }
+ if (ret < 0)
+ goto out;
+ free(var);
+ var = tmp;
+ /* We need to compare current p again */
+ p--;
+ break;
+ case '-':
+ p++;
+ if (*p != '>') {
+ ccli_printf(ccli, "# Invalid variable '%s'\n",
+ type);
+ goto out;
+ }
+ p++;
+ if (*p == '-') {
+ p++;
+ neg = true;
+ }
+ offset = strtoll(p, &end, 0);
+ ret = asprintf(&tmp, "%s%llu(%s)",
+ neg ? "-" : "+", offset, var);
+ if (ret < 0)
+ goto out;
+ free(var);
+ var = tmp;
+ break;
+ }
+ }
+ /* Finished */
+ ret = asprintf(&tmp, "%s %s=%s", *command, line, var);
+ out:
+ free(var);
+ if (ret < 0)
+ return -1;
+ free(*command);
+ *command = tmp;
+ return 0;
+}
+
+static int create_eprobe(struct ccli *ccli, void *data,
+ int argc, char **argv)
+{
+ struct tep_handle *tep = data;
+ struct tep_event *event;
+ char *command;
+ char *system;
+ char *ename;
+ char *name;
+ char *sav;
+ int ret;
+ int i;
+
+ if (argc < 3) {
+ ccli_printf(ccli, "# usage: create eprobe name system/event fields\n");
+ return 0;
+ }
+
+ name = argv[0];
+
+ system = strtok_r(argv[1], "/", &sav);
+ ename = strtok_r(NULL, "/", &sav);
+ if (!ename) {
+ event = tep_find_event_by_name(tep, NULL, system);
+ if (!event) {
+ ccli_printf(ccli, "# Event %s not found\n", system);
+ return 0;
+ }
+ system = event->system;
+ } else {
+ event = tep_find_event_by_name(tep, system, ename);
+ if (!event) {
+ ccli_printf(ccli, "# Event %s/%s not found\n",
+ system, ename);
+ return 0;
+ }
+ }
+
+ ret = asprintf(&command, "e:%s %s/%s", name, system, ename);
+ if (ret < 0)
+ return 0;
+
+ for (i = 2 ; i < argc; i++ ) {
+ ret = add_event_var(ccli, tep, &command, event, argv[i]);
+ if (ret < 0)
+ goto out;
+ }
+ ccli_printf(ccli, "# echo '%s' >> %s/dynamic_events\n",
+ command, tracefs_tracing_dir());
+ out:
+ free(command);
+ return 0;
+}
+
+int cmd_create(struct ccli *ccli, const char *command, const char *line,
+ void *data, int argc, char **argv)
+{
+ if (argc < 2) {
+ create_usage(ccli);
+ return 0;
+ }
+
+ if (strcmp(argv[1], "kprobe") == 0)
+ return create_kprobe(ccli, data, argc - 2, argv + 2);
+
+ if (strcmp(argv[1], "eprobe") == 0)
+ return create_eprobe(ccli, data, argc - 2, argv + 2);
+
+ return 0;
+}
+
+static int kprobe_completion(struct ccli *ccli, void *data,
+ int argc, char **argv,
+ char ***list, int word, char *match)
+{
+ return 0;
+}
+
+static int eprobe_completion(struct ccli *ccli, void *data,
+ int argc, char **argv,
+ char ***list, int word, char *match)
+{
+ struct tep_handle *tep = data;
+ struct tep_format_field **common_fields;
+ struct tep_format_field **fields;
+ struct tep_event *event;
+ static char *types[] = {"string" , "ustring", "x8", "x16", "x32", "x64",
+ "u8", "u16", "u32", "u64", "s8", "s16", "s32", "s64" };
+ char **systems;
+ char **events;
+ char **words;
+ char **tmp;
+ char *system;
+ char *name;
+ char *sav;
+ char *p, *m;
+ int len;
+ int i, x;
+
+ switch (word) {
+ case 0:
+ ccli_printf(ccli, "\n# Name the event probe\n");
+ ccli_line_refresh(ccli);
+ return 0;
+ case 1:
+ p = strchr(match, '/');
+ if (p) {
+ system = strdup(match);
+ if (!system)
+ return 0;
+ system[p - match] = '\0';
+ events = tracefs_system_events(NULL, system);
+ if (!events) {
+ free(system);
+ return 0;
+ }
+ words = calloc(tracefs_list_size(events), sizeof(char *));
+ i = 0;
+ if (words) {
+ for (; events[i]; i++)
+ asprintf(words + i, "%s/%s",
+ system, events[i]);
+ }
+ tracefs_list_free(events);
+ } else {
+ systems = tracefs_event_systems(NULL);
+ if (!systems)
+ return 0;
+ words = calloc(tracefs_list_size(systems), sizeof(char *));
+ i = 0;
+ if (words) {
+ for (; systems[i]; i++)
+ words[i] = strdup(systems[i]);
+ }
+ tracefs_list_free(systems);
+ /* Use '/' as a delim */
+ match[strlen(match)] = '/';
+ }
+ *list = words;
+ return i;
+ default:
+ system = strtok_r(argv[1], "/", &sav);
+ name = strtok_r(NULL, "/", &sav);
+ if (!system || !name)
+ return 0;
+ event = tep_find_event_by_name(tep, system, name);
+ if (!event) {
+ ccli_printf(ccli, "\n# Event %s/%s not found\n",
+ system, name);
+ return 0;
+ }
+ p = strchr(match, '=');
+ if (!p) {
+ ccli_printf(ccli, "\n# var=field[.type][->offset[.type]\n");
+ ccli_line_refresh(ccli);
+ return 0;
+ }
+ m = p;
+ while (*p) {
+ if (*p == '.' || *p == '-')
+ m = p;
+ p++;
+ }
+
+ len = m - match;
+
+ switch (*m) {
+ default:
+ common_fields = tep_event_common_fields(event);
+ fields = tep_event_fields(event);
+ words = NULL;
+ x = 0;
+ for (i = 0; common_fields && common_fields[i]; i++) {
+ tmp = realloc(words, sizeof(char *) * (x + 2));
+ if (!tmp) {
+ ccli_argv_free(words);
+ return 0;
+ }
+ words = tmp;
+ asprintf(&words[x++], "%.*s=%s",
+ len, match,
+ common_fields[i]->name);
+ words[x] = NULL;
+ }
+ for (i = 0; fields && fields[i]; i++) {
+ tmp = realloc(words, sizeof(char *) * (x + 2));
+ if (!tmp) {
+ ccli_argv_free(words);
+ return 0;
+ }
+ words = tmp;
+ asprintf(&words[x++], "%.*s=%s",
+ len, match,
+ fields[i]->name);
+ words[x] = NULL;
+ }
+ free(common_fields);
+ free(fields);
+ *list = words;
+ match[strlen(match)] = CCLI_NOSPACE;
+ return x;
+ case '.':
+ x = ARRAY_SIZE(types);
+ words = calloc(x, sizeof(char *));
+ if (!words)
+ return 0;
+ for (i = 0; i < x; i++) {
+ asprintf(&words[i], "%.*s.%s",
+ len, match, types[i]);
+ }
+ *list = words;
+ match[strlen(match)] = CCLI_NOSPACE;
+ return x;
+ case '-':
+ if (!m[1]) {
+ words = calloc(1, sizeof(char *));
+ if (!words)
+ return 0;
+ asprintf(&words[0], "%.*s->",
+ len, match);
+ *list = words;
+ match[strlen(match)] = CCLI_NOSPACE;
+ return 1;
+ }
+ return 0;
+ }
+ }
+ printf("\neprobe word=%d match=%s\n", word, match);
+ return 0;
+}
+
+int create_completion(struct ccli *ccli, const char *command,
+ const char *line, int word,
+ char *match, char ***list, void *data)
+{
+ char *types[] = { "kprobe", "eprobe", "synthetic" };
+ char **words;
+ char **argv;
+ int argc;
+ int ret = 0;
+ int i;
+
+ if (word == 1) {
+ words = calloc(ARRAY_SIZE(types), sizeof(char *));
+ if (!words)
+ return 0;
+ for (i = 0; i < ARRAY_SIZE(types); i++)
+ words[i] = strdup(types[i]);
+ *list = words;
+ return i;
+ }
+
+ argc = ccli_line_parse(line, &argv);
+ if (argc < 0)
+ return 0;
+
+ if (strcmp(argv[1], "kprobe") == 0)
+ ret = kprobe_completion(ccli, data, argc - 2, argv + 2,
+ list, word - 2, match);
+
+ if (strcmp(argv[1], "eprobe") == 0)
+ ret = eprobe_completion(ccli, data, argc - 2, argv + 2,
+ list, word - 2, match);
+
+ ccli_argv_free(argv);
+
+ return ret;
+}
diff --git a/src/ktrace.c b/src/ktrace.c
new file mode 100644
index 0000000..db4b560
--- /dev/null
+++ b/src/ktrace.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Google Inc, Steven Rostedt <rostedt@goodmis.org>
+ */
+#include "ktrace.h"
+
+#define EXEC_NAME "ktrace"
+
+static void usage(char **argv)
+{
+ printf("usage: %s\n"
+ "\n", EXEC_NAME);
+ exit(-1);
+}
+
+static void __vdie(const char *fmt, va_list ap, int err)
+{
+ int ret = errno;
+
+ if (err && errno)
+ perror(EXEC_NAME);
+ else
+ ret = -1;
+
+ fprintf(stderr, " ");
+ vfprintf(stderr, fmt, ap);
+
+ fprintf(stderr, "\n");
+ exit(ret);
+}
+
+void pdie(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __vdie(fmt, ap, 1);
+ va_end(ap);
+}
+
+int main (int argc, char **argv)
+{
+ struct ccli *ccli;
+ struct tep_handle *tep;
+
+ tep = tracefs_local_events(NULL);
+ if (!tep) {
+ if (errno == EPERM)
+ pdie("Failed to initialize tracing directory.\n"
+ " You do not have permission to read it");
+ pdie("Failed to initialize tracing directory");
+ }
+ ccli = ccli_alloc("ktrace> ", STDIN_FILENO, STDOUT_FILENO);
+ if (!ccli)
+ pdie("ccli initialization");
+
+ ccli_register_command(ccli, "create", cmd_create, tep);
+ ccli_register_completion(ccli, "create", create_completion);
+
+ ccli_loop(ccli);
+ ccli_free(ccli);
+
+ tep_free(tep);
+
+ return 0;
+}
diff --git a/src/ktrace.h b/src/ktrace.h
new file mode 100644
index 0000000..1b8853c
--- /dev/null
+++ b/src/ktrace.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KTRACE__H
+#define __KTRACE__H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <tracefs.h>
+#include <ccli.h>
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+
+int create_completion(struct ccli *ccli, const char *command,
+ const char *line, int word,
+ char *match, char ***list, void *data);
+int cmd_create(struct ccli *ccli, const char *command, const char *line,
+ void *data, int argc, char **argv);
+
+#endif