From 27caca78522727c29c777d3697d007a2fe9724c6 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 18 Feb 2021 11:21:33 -0500 Subject: [PATCH] Initial commit Signed-off-by: Mathieu Desnoyers --- LICENSE | 6 + LICENSES/GPL-2.0 | 353 +++++++++++++++++ LICENSES/MIT | 30 ++ Makefile.am | 16 + README.md | 6 + bootstrap | 9 + configure.ac | 106 +++++ m4/ax_c___attribute__.m4 | 66 ++++ m4/ax_pthread.m4 | 486 +++++++++++++++++++++++ m4/pprint.m4 | 210 ++++++++++ src/Makefile.am | 13 + src/lttng-trace.c | 806 +++++++++++++++++++++++++++++++++++++++ 12 files changed, 2107 insertions(+) create mode 100644 LICENSE create mode 100644 LICENSES/GPL-2.0 create mode 100644 LICENSES/MIT create mode 100644 Makefile.am create mode 100644 README.md create mode 100755 bootstrap create mode 100644 configure.ac create mode 100644 m4/ax_c___attribute__.m4 create mode 100644 m4/ax_pthread.m4 create mode 100644 m4/pprint.m4 create mode 100644 src/Makefile.am create mode 100644 src/lttng-trace.c diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d466d47 --- /dev/null +++ b/LICENSE @@ -0,0 +1,6 @@ +This program is provided under: + + SPDX-License-Identifier: GPL-2.0-only + +In addition, other licenses may also apply. See individual files SPDX License +Identifiers for details. diff --git a/LICENSES/GPL-2.0 b/LICENSES/GPL-2.0 new file mode 100644 index 0000000..cdd31bf --- /dev/null +++ b/LICENSES/GPL-2.0 @@ -0,0 +1,353 @@ +Valid-License-Identifier: GPL-2.0-only +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-only + For 'GNU General Public License (GPL) version 2 or any later version' use: + 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 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. + + + Copyright (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., 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. + + , 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. diff --git a/LICENSES/MIT b/LICENSES/MIT new file mode 100644 index 0000000..f33a68c --- /dev/null +++ b/LICENSES/MIT @@ -0,0 +1,30 @@ +Valid-License-Identifier: MIT +SPDX-URL: https://spdx.org/licenses/MIT.html +Usage-Guide: + To use the MIT License put the following SPDX tag/value pair into a + comment according to the placement guidelines in the licensing rules + documentation: + SPDX-License-Identifier: MIT +License-Text: + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..b0aff70 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: MIT +# +# Copyright (C) 2019 Michael Jeanson +# + +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = \ + src + +dist_doc_DATA = README.md + +EXTRA_DIST = \ + LICENSE \ + LICENSES/GPL-2.0 \ + LICENSES/MIT diff --git a/README.md b/README.md new file mode 100644 index 0000000..4a39fa5 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +LTTng trace - Trace command execution and its sub-processes +===================================================================== + +by Mathieu Desnoyers + +TODO diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..ace8016 --- /dev/null +++ b/bootstrap @@ -0,0 +1,9 @@ +#!/bin/sh +# SPDX-License-Identifier: MIT + +set -x +if [ ! -d "config" ]; then + mkdir config +fi + +autoreconf -vi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..3720009 --- /dev/null +++ b/configure.ac @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: MIT +# +# Copyright (C) 2019 Michael Jeanson +# + +AC_PREREQ(2.59) +AC_INIT([lttng-trace],[0.1.0-pre],[mathieu dot desnoyers at efficios dot com], [], [https://github.com/compudj/lttng-trace/]) + +AC_CONFIG_HEADERS([include/config.h]) +AC_CONFIG_AUX_DIR([config]) +AC_CONFIG_MACRO_DIR([m4]) + +AC_CANONICAL_TARGET +AC_CANONICAL_HOST + +AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip nostdinc]) +AM_MAINTAINER_MODE([enable]) + +# Enable silent rules if available (Introduced in AM 1.11) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +# Checks for C compiler +AC_USE_SYSTEM_EXTENSIONS +AC_PROG_CC +AC_PROG_CC_STDC +AC_PROG_CXX + +# Checks for programs. +AC_PROG_AWK +AC_PROG_MAKE_SET + +LT_INIT + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T + +AX_C___ATTRIBUTE__ +AS_IF([test "x$ax_cv___attribute__" = "xyes"], + [:], + [AC_MSG_ERROR([The compiler does not support __attribute__ extensions])]) + +AX_PTHREAD(,[AC_MSG_ERROR([Could not configure pthreads support])]) + +AM_CFLAGS="$AM_CFLAGS $PTHREAD_CFLAGS" + +# Checks for library functions. +AC_FUNC_MMAP +AC_FUNC_FORK +AC_CHECK_FUNCS([ \ + memset \ + strerror \ +]) + +# AC_FUNC_MALLOC causes problems when cross-compiling. +#AC_FUNC_MALLOC + +# Check for headers +AC_HEADER_STDBOOL +AC_CHECK_HEADERS([ \ + limits.h \ + stddef.h \ +]) + +AM_CPPFLAGS="-include config.h" +AC_SUBST(AM_CPPFLAGS) + +AM_CFLAGS="-Wall -Wextra $AM_CFLAGS" +AC_SUBST(AM_CFLAGS) + +AC_CONFIG_FILES([ + Makefile + src/Makefile +]) + +AC_OUTPUT + +# +# Mini-report on what will be built. +# + +PPRINT_INIT +PPRINT_SET_INDENT(1) +PPRINT_SET_TS(38) + +AS_ECHO +AS_ECHO("${PPRINT_COLOR_BLDBLU}lttng-trace $PACKAGE_VERSION${PPRINT_COLOR_RST}") +AS_ECHO + +PPRINT_SUBTITLE([Features]) + +PPRINT_PROP_STRING([Target architecture], $host_cpu) + +report_bindir="`eval eval echo $bindir`" +report_libdir="`eval eval echo $libdir`" + +# Print the bindir and libdir this `make install' will install into. +AS_ECHO +PPRINT_SUBTITLE([Install directories]) +PPRINT_PROP_STRING([Binaries], [$report_bindir]) +PPRINT_PROP_STRING([Libraries], [$report_libdir]) diff --git a/m4/ax_c___attribute__.m4 b/m4/ax_c___attribute__.m4 new file mode 100644 index 0000000..6a1ede1 --- /dev/null +++ b/m4/ax_c___attribute__.m4 @@ -0,0 +1,66 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_c___attribute__.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_C___ATTRIBUTE__ +# +# DESCRIPTION +# +# Provides a test for the compiler support of __attribute__ extensions. +# Defines HAVE___ATTRIBUTE__ if it is found. +# +# LICENSE +# +# Copyright (c) 2008 Stepan Kasal +# Copyright (c) 2008 Christian Haggstrom +# Copyright (c) 2008 Ryan McCabe +# +# 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, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 9 + +AC_DEFUN([AX_C___ATTRIBUTE__], [ + AC_CACHE_CHECK([for __attribute__], [ax_cv___attribute__], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + static void foo(void) __attribute__ ((unused)); + static void + foo(void) { + exit(1); + } + ]], [])], + [ax_cv___attribute__=yes], + [ax_cv___attribute__=no] + ) + ]) + if test "$ax_cv___attribute__" = "yes"; then + AC_DEFINE([HAVE___ATTRIBUTE__], 1, [define if your compiler has __attribute__]) + fi +]) diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4 new file mode 100644 index 0000000..4920e07 --- /dev/null +++ b/m4/ax_pthread.m4 @@ -0,0 +1,486 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_pthread.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro figures out how to build C programs using POSIX threads. It +# sets the PTHREAD_LIBS output variable to the threads library and linker +# flags, and the PTHREAD_CFLAGS output variable to any special C compiler +# flags that are needed. (The user can also force certain compiler +# flags/libs to be tested by setting these environment variables.) +# +# Also sets PTHREAD_CC to any special C compiler that is needed for +# multi-threaded programs (defaults to the value of CC otherwise). (This +# is necessary on AIX to use the special cc_r compiler alias.) +# +# NOTE: You are assumed to not only compile your program with these flags, +# but also to link with them as well. For example, you might link with +# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# +# If you are only building threaded programs, you may wish to use these +# variables in your default LIBS, CFLAGS, and CC: +# +# LIBS="$PTHREAD_LIBS $LIBS" +# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +# CC="$PTHREAD_CC" +# +# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# +# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the +# PTHREAD_PRIO_INHERIT symbol is defined when compiling with +# PTHREAD_CFLAGS. +# +# ACTION-IF-FOUND is a list of shell commands to run if a threads library +# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it +# is not found. If ACTION-IF-FOUND is not specified, the default action +# will define HAVE_PTHREAD. +# +# Please let the authors know if this macro fails on any platform, or if +# you have any other suggestions or comments. This macro was based on work +# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help +# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by +# Alejandro Forero Cuervo to the autoconf macro repository. We are also +# grateful for the helpful feedback of numerous users. +# +# Updated for Autoconf 2.68 by Daniel Richard G. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2011 Daniel Richard G. +# +# 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 3 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, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 25 + +AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) +AC_DEFUN([AX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) +AC_LANG_PUSH([C]) +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on Tru64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; +esac + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) + +# Are we compiling with Clang? + +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + +ax_pthread_clang_warning=no + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -mt,pthread) + AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) + + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) + + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT; + return i;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + ;; + esac + fi +fi + +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + +AC_SUBST([PTHREAD_LIBS]) +AC_SUBST([PTHREAD_CFLAGS]) +AC_SUBST([PTHREAD_CC]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "x$ax_pthread_ok" = "xyes"; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : +else + ax_pthread_ok=no + $2 +fi +AC_LANG_POP +])dnl AX_PTHREAD diff --git a/m4/pprint.m4 b/m4/pprint.m4 new file mode 100644 index 0000000..a7cfd94 --- /dev/null +++ b/m4/pprint.m4 @@ -0,0 +1,210 @@ +# Pretty printing macros. +# +# Author: Philippe Proulx + +#serial 1 + +# PPRINT_INIT(): initializes the pretty printing system. +# +# Use this macro before using any other PPRINT_* macro. +AC_DEFUN([PPRINT_INIT], [ + m4_define([PPRINT_CONFIG_TS], [50]) + m4_define([PPRINT_CONFIG_INDENT], [2]) + PPRINT_YES_MSG=yes + PPRINT_NO_MSG=no + + # find tput, which tells us if colors are supported and gives us color codes + AC_PATH_PROG([pprint_tput], [tput]) + + AS_IF([test -n "$pprint_tput"], [ + AS_IF([test -n "$PS1" && test `"$pprint_tput" colors` -eq 256 && test -t 1], [ + # interactive shell and colors supported and standard output + # file descriptor is opened on a terminal + PPRINT_COLOR_TXTBLK="`"$pprint_tput" setaf 0`" + PPRINT_COLOR_TXTBLU="`"$pprint_tput" setaf 4`" + PPRINT_COLOR_TXTGRN="`"$pprint_tput" setaf 2`" + PPRINT_COLOR_TXTCYN="`"$pprint_tput" setaf 6`" + PPRINT_COLOR_TXTRED="`"$pprint_tput" setaf 1`" + PPRINT_COLOR_TXTPUR="`"$pprint_tput" setaf 5`" + PPRINT_COLOR_TXTYLW="`"$pprint_tput" setaf 3`" + PPRINT_COLOR_TXTWHT="`"$pprint_tput" setaf 7`" + PPRINT_COLOR_BLD=`"$pprint_tput" bold` + PPRINT_COLOR_BLDBLK="$PPRINT_COLOR_BLD$PPRINT_COLOR_TXTBLK" + PPRINT_COLOR_BLDBLU="$PPRINT_COLOR_BLD$PPRINT_COLOR_TXTBLU" + PPRINT_COLOR_BLDGRN="$PPRINT_COLOR_BLD$PPRINT_COLOR_TXTGRN" + PPRINT_COLOR_BLDCYN="$PPRINT_COLOR_BLD$PPRINT_COLOR_TXTCYN" + PPRINT_COLOR_BLDRED="$PPRINT_COLOR_BLD$PPRINT_COLOR_TXTRED" + PPRINT_COLOR_BLDPUR="$PPRINT_COLOR_BLD$PPRINT_COLOR_TXTPUR" + PPRINT_COLOR_BLDYLW="$PPRINT_COLOR_BLD$PPRINT_COLOR_TXTYLW" + PPRINT_COLOR_BLDWHT="$PPRINT_COLOR_BLD$PPRINT_COLOR_TXTWHT" + PPRINT_COLOR_RST="`"$pprint_tput" sgr0`" + + # colored yes and no + PPRINT_YES_MSG="$PPRINT_COLOR_BLDGRN$PPRINT_YES_MSG$PPRINT_COLOR_RST" + PPRINT_NO_MSG="$PPRINT_COLOR_BLDRED$PPRINT_NO_MSG$PPRINT_COLOR_RST" + + # subtitle color + PPRINT_COLOR_SUBTITLE="$PPRINT_COLOR_BLDCYN" + ]) + ]) +]) + +# PPRINT_SET_INDENT(indent): sets the current indentation. +# +# Use PPRINT_INIT() before using this macro. +AC_DEFUN([PPRINT_SET_INDENT], [ + m4_define([PPRINT_CONFIG_INDENT], [$1]) +]) + +# PPRINT_SET_TS(ts): sets the current tab stop. +# +# Use PPRINT_INIT() before using this macro. +AC_DEFUN([PPRINT_SET_TS], [ + m4_define([PPRINT_CONFIG_TS], [$1]) +]) + +# PPRINT_SUBTITLE(subtitle): pretty prints a subtitle. +# +# The subtitle is put as is in a double-quoted shell string so the user +# needs to escape ". +# +# Use PPRINT_INIT() before using this macro. +AC_DEFUN([PPRINT_SUBTITLE], [ + AS_ECHO(["${PPRINT_COLOR_SUBTITLE}$1$PPRINT_COLOR_RST"]) +]) + +AC_DEFUN([_PPRINT_INDENT], [ + m4_if(PPRINT_CONFIG_INDENT, 0, [ + ], [ + m4_for([pprint_i], [0], m4_eval(PPRINT_CONFIG_INDENT * 2 - 1), [1], [ + AS_ECHO_N([" "]) + ]) + ]) +]) + +# PPRINT_PROP_STRING(title, value, title_color?): pretty prints a +# string property. +# +# The title is put as is in a double-quoted shell string so the user +# needs to escape ". +# +# The $PPRINT_CONFIG_INDENT variable must be set to the desired indentation +# level. +# +# Use PPRINT_INIT() before using this macro. +AC_DEFUN([PPRINT_PROP_STRING], [ + m4_pushdef([pprint_title], [$1]) + m4_pushdef([pprint_value], [$2]) + m4_pushdef([pprint_title_color], m4_default([$3], [])) + m4_pushdef([pprint_title_len], m4_len(pprint_title)) + m4_pushdef([pprint_spaces_cnt], m4_eval(PPRINT_CONFIG_TS - pprint_title_len - (PPRINT_CONFIG_INDENT * 2) - 1)) + + m4_if(m4_eval(pprint_spaces_cnt <= 0), [1], [ + m4_define([pprint_spaces_cnt], [1]) + ]) + + m4_pushdef([pprint_spaces], []) + + m4_for([pprint_i], 0, m4_eval(pprint_spaces_cnt - 1), [1], [ + m4_append([pprint_spaces], [ ]) + ]) + + _PPRINT_INDENT + + AS_ECHO_N(["pprint_title_color""pprint_title$PPRINT_COLOR_RST:pprint_spaces"]) + AS_ECHO(["${PPRINT_COLOR_BLD}pprint_value$PPRINT_COLOR_RST"]) + + m4_popdef([pprint_spaces]) + m4_popdef([pprint_spaces_cnt]) + m4_popdef([pprint_title_len]) + m4_popdef([pprint_title_color]) + m4_popdef([pprint_value]) + m4_popdef([pprint_title]) +]) + +# PPRINT_PROP_BOOL(title, value, title_color?): pretty prints a boolean +# property. +# +# The title is put as is in a double-quoted shell string so the user +# needs to escape ". +# +# The value is evaluated at shell runtime. Its evaluation must be +# 0 (false) or 1 (true). +# +# Uses the PPRINT_PROP_STRING() with the "yes" or "no" string. +# +# Use PPRINT_INIT() before using this macro. +AC_DEFUN([PPRINT_PROP_BOOL], [ + m4_pushdef([pprint_title], [$1]) + m4_pushdef([pprint_value], [$2]) + + test pprint_value -eq 0 && pprint_msg="$PPRINT_NO_MSG" || pprint_msg="$PPRINT_YES_MSG" + + m4_if([$#], [3], [ + PPRINT_PROP_STRING(pprint_title, [$pprint_msg], $3) + ], [ + PPRINT_PROP_STRING(pprint_title, [$pprint_msg]) + ]) + + m4_popdef([pprint_value]) + m4_popdef([pprint_title]) +]) + +# PPRINT_PROP_BOOL_CUSTOM(title, value, no_msg, title_color?): pretty prints a boolean +# property. +# +# The title is put as is in a double-quoted shell string so the user +# needs to escape ". +# +# The value is evaluated at shell runtime. Its evaluation must be +# 0 (false) or 1 (true). +# +# Uses the PPRINT_PROP_STRING() with the "yes" or "no" string. +# +# Use PPRINT_INIT() before using this macro. +AC_DEFUN([PPRINT_PROP_BOOL_CUSTOM], [ + m4_pushdef([pprint_title], [$1]) + m4_pushdef([pprint_value], [$2]) + m4_pushdef([pprint_value_no_msg], [$3]) + + test pprint_value -eq 0 && pprint_msg="$PPRINT_NO_MSG (pprint_value_no_msg)" || pprint_msg="$PPRINT_YES_MSG" + + m4_if([$#], [4], [ + PPRINT_PROP_STRING(pprint_title, [$pprint_msg], $4) + ], [ + PPRINT_PROP_STRING(pprint_title, [$pprint_msg]) + ]) + + m4_popdef([pprint_value_no_msg]) + m4_popdef([pprint_value]) + m4_popdef([pprint_title]) +]) + +# PPRINT_WARN(msg): pretty prints a warning message. +# +# The message is put as is in a double-quoted shell string so the user +# needs to escape ". +# +# Use PPRINT_INIT() before using this macro. +AC_DEFUN([PPRINT_WARN], [ + m4_pushdef([pprint_msg], [$1]) + + _PPRINT_INDENT + AS_ECHO(["${PPRINT_COLOR_TXTYLW}WARNING:$PPRINT_COLOR_RST ${PPRINT_COLOR_BLDYLW}pprint_msg$PPRINT_COLOR_RST"]) + + m4_popdef([pprint_msg]) +]) + +# PPRINT_ERROR(msg): pretty prints an error message and exits. +# +# The message is put as is in a double-quoted shell string so the user +# needs to escape ". +# +# Use PPRINT_INIT() before using this macro. +AC_DEFUN([PPRINT_ERROR], [ + m4_pushdef([pprint_msg], [$1]) + + AC_MSG_ERROR([${PPRINT_COLOR_BLDRED}pprint_msg$PPRINT_COLOR_RST]) + + m4_popdef([pprint_msg]) +]) diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..982379c --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: MIT +# +# Copyright (C) 2019 Michael Jeanson +# + +AM_CPPFLAGS += -I$(top_srcdir)/include -I$(top_builddir)/include + +bin_PROGRAMS = lttng-trace + +lttng_trace_SOURCES = \ + lttng-trace.c + +lttng_trace_LDADD = -llttng-ctl diff --git a/src/lttng-trace.c b/src/lttng-trace.c new file mode 100644 index 0000000..7cef913 --- /dev/null +++ b/src/lttng-trace.c @@ -0,0 +1,806 @@ +/* + * Copyright (c) 2015-2021 Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 only, + * as published by the Free Software Foundation. + * + * 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. + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MESSAGE_PREFIX "[lttng-ptrace] " +#define NR_HANDLES 2 + +#ifndef PTRACE_EVENT_STOP +#define PTRACE_EVENT_STOP 128 +#endif + +#define PERROR(msg) perror(msg "\n") +#define ERR(fmt, args...) fprintf(stderr, fmt, ## args) + +#ifdef DEBUG +#define DBG(fmt, args...) printf(fmt, ## args) +#else +#define DBG(fmt, args...) +#endif + +#define __unused __attribute__((unused)) + +static pid_t sigfwd_pid; + +static bool opt_help = false, + opt_no_context = false, + opt_no_pause = false, + opt_no_syscall = false, + opt_session = false, + opt_view = false, + opt_output = false; + +static const char *output_path; +static const char *session_name; + +struct lttng_trace_ctx { + char session_name[LTTNG_NAME_MAX]; + char path[PATH_MAX]; + time_t creation_time; +}; + +static +long ptrace_setup(pid_t pid) +{ + long ptrace_ret; + unsigned long flags; + + flags = PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXIT + | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK + | PTRACE_O_TRACEEXEC; + //ptrace_ret = ptrace(PTRACE_SETOPTIONS, pid, + ptrace_ret = ptrace(PTRACE_SEIZE, pid, + NULL, (void *) flags); + if (ptrace_ret) { + //PERROR("ptrace setoptions"); + PERROR("ptrace seize"); + return -1; + } + return 0; +} + +static +int wait_on_children(pid_t top_pid, struct lttng_handle **handle, + size_t nr_handles) +{ + pid_t pid; + long ptrace_ret; + int ret; + size_t i; + + pid = top_pid; + DBG("Setup ptrace options on top child pid %d", pid); + ret = ptrace_setup(pid); + if (ret) { + return ret; + } + for (i = 0; i < nr_handles; i++) { + ret = lttng_track_pid(handle[i], pid); + if (ret && ret != -LTTNG_ERR_INVALID) { + ERR("Error %d tracking pid %d", ret, pid); + } + } + top_pid = -1; + /* Restart initial raise(SIGSTOP) */ + //ptrace_ret = ptrace(PTRACE_CONT, pid, 0, restartsig); + //TODO wait for child to have stopped.... + ret = kill(pid, SIGCONT); + if (ret) { + //if (ptrace_ret) { + PERROR("kill"); + abort(); + } + + for (;;) { + int status; + + pid = waitpid(-1, &status, __WALL); + DBG("Activity on child pid %d", pid); + if (pid < 0) { + if (errno == ECHILD) { + /* No more children to possibly wait for. */ + return 0; + } else { + PERROR("waitpid"); + return -1; + } + } else if (pid == 0) { + ERR("Unexpected PID 0"); + abort(); + } else { + if (WIFSTOPPED(status)) { + int shiftstatus, restartsig; + + DBG("Child pid %d is stopped", pid); + shiftstatus = status >> 8; + if (shiftstatus == (SIGTRAP | (PTRACE_EVENT_EXIT << 8))) { + DBG("Child pid %d is exiting", pid); +#if 0 + for (i = 0; i < nr_handles; i++) { + ret = lttng_untrack_pid(handle[i], pid); + if (ret && ret != -LTTNG_ERR_INVALID) { + ERR("Error %d untracking pid %d", ret, pid); + } + } +#endif + } else if (shiftstatus == (SIGTRAP | (PTRACE_EVENT_FORK << 8))) { + long newpid; + + ptrace_ret = ptrace(PTRACE_GETEVENTMSG, pid, 0, &newpid); + if (ptrace_ret) { + PERROR("ptrace"); + abort(); + } + DBG("Child pid %d is forking, child pid %ld", pid, newpid); + for (i = 0; i < nr_handles; i++) { + ret = lttng_track_pid(handle[i], newpid); + if (ret && ret != -LTTNG_ERR_INVALID) { + ERR("Error %d tracking pid %ld", ret, newpid); + } + } + } else if (shiftstatus == (SIGTRAP | (PTRACE_EVENT_VFORK << 8))) { + long newpid; + + ptrace_ret = ptrace(PTRACE_GETEVENTMSG, pid, 0, &newpid); + if (ptrace_ret) { + PERROR("ptrace"); + abort(); + } + DBG("Child pid %d issuing vfork, child pid %ld", pid, newpid); + for (i = 0; i < nr_handles; i++) { + ret = lttng_track_pid(handle[i], newpid); + if (ret && ret != -LTTNG_ERR_INVALID) { + ERR("Error %d tracking pid %ld", ret, newpid); + } + } + } else if (shiftstatus == (SIGTRAP | PTRACE_EVENT_CLONE << 8)) { + long newpid; + + ptrace_ret = ptrace(PTRACE_GETEVENTMSG, pid, 0, &newpid); + if (ptrace_ret) { + PERROR("ptrace"); + abort(); + } + DBG("Child pid %d issuing clone, child pid %ld", pid, newpid); + for (i = 0; i < nr_handles; i++) { + ret = lttng_track_pid(handle[i], newpid); + if (ret && ret != -LTTNG_ERR_INVALID) { + ERR("Error %d tracking pid %ld", ret, newpid); + } + } + } else if (shiftstatus == (SIGTRAP | PTRACE_EVENT_EXEC << 8)) { + long oldpid; + + ptrace_ret = ptrace(PTRACE_GETEVENTMSG, pid, 0, &oldpid); + if (ptrace_ret) { + PERROR("ptrace"); + abort(); + } + DBG("Child pid (old: %ld, new: %d) is issuing exec", + oldpid, pid); + /* + * Needed for exec issued from + * multithreaded process. + */ + for (i = 0; i < nr_handles; i++) { + ret = lttng_untrack_pid(handle[i], oldpid); + if (ret && ret != -LTTNG_ERR_INVALID) { + ERR("Error %d untracking pid %ld", ret, oldpid); + } + ret = lttng_track_pid(handle[i], pid); + if (ret && ret != -LTTNG_ERR_INVALID) { + ERR("Error %d tracking pid %d", ret, pid); + } + } + } else if (shiftstatus == SIGTRAP) { + DBG("Received SIGTRAP from pid %d without event of interest", pid); + } else if (shiftstatus == SIGSTOP) { + DBG("Received SIGSTOP from pid %d without event of interest", pid); + } else if (shiftstatus == SIGSEGV) { + DBG("Received SIGSEGV from pid %d without event of interest", pid); + } else if (shiftstatus == SIGTTIN) { + DBG("Received SIGTTIN from pid %d without event of interest", pid); + } else if (shiftstatus == SIGTTOU) { + DBG("Received SIGTTOU from pid %d without event of interest", pid); + } else if (shiftstatus == SIGTSTP) { + DBG("Received SIGTSTP from pid %d without event of interest", pid); + } else { + DBG("Ignoring signal %d (status %d) from pid %d (eventcode = %u)", + WSTOPSIG(status), status, pid, + (shiftstatus & ~WSTOPSIG(status)) >> 8); + } + + restartsig = WSTOPSIG(status); + switch (restartsig) { + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + case SIGSTOP: + { + //siginfo_t siginfo; + + errno = 0; + //ptrace_ret = ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo); + //if (ptrace_ret < 0 && errno == EINVAL) { + if (restartsig == SIGTTIN) { + ret = kill(pid, SIGTTIN); + if (ret) { + PERROR("kill"); + abort(); + } + } else if (status >> 16 == PTRACE_EVENT_STOP) { + DBG("ptrace stop"); + //ptrace_ret = ptrace(PTRACE_LISTEN, pid, 0, 0); + ptrace_ret = ptrace(PTRACE_CONT, pid, 0, 0); + if (ptrace_ret) { + PERROR("ptrace cont"); + abort(); + } + } else { + DBG("job control stop ret %ld errno %d", ptrace_ret, errno); + /* + * It's not a group-stop, so restart process, + * skipping the signal. + */ + ptrace_ret = ptrace(PTRACE_CONT, pid, 0, 0); + if (ptrace_ret) { + PERROR("ptrace cont"); + abort(); + } + } + break; + } + case SIGTRAP: + { + //unsigned long data; + + //if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data) == 0) { + /* + * Restart process skipping the signal when + * receiving a message. + */ + ptrace_ret = ptrace(PTRACE_CONT, pid, 0, 0); + if (ptrace_ret) { + PERROR("ptrace"); + abort(); + } + break; + //} + } + /* Fall-through */ + default: + /* Restart with original signal. */ + ptrace_ret = ptrace(PTRACE_CONT, pid, 0, restartsig); + if (ptrace_ret) { + PERROR("ptrace"); + abort(); + } + } + } else if (WIFEXITED(status)) { + DBG("Child pid %d exited normally with status %d", + pid, WEXITSTATUS(status)); + for (i = 0; i < nr_handles; i++) { + ret = lttng_untrack_pid(handle[i], pid); + if (ret && ret != -LTTNG_ERR_INVALID) { + ERR("Error %d tracking pid %d", ret, pid); + } + } + } else if (WIFSIGNALED(status)) { + DBG("Child pid %d terminated by signal %d", pid, + WTERMSIG(status)); + for (i = 0; i < nr_handles; i++) { + ret = lttng_untrack_pid(handle[i], pid); + if (ret && ret != -LTTNG_ERR_INVALID) { + ERR("Error %d tracking pid %d", ret, pid); + } + } + } else { + DBG("Unhandled status %d from child %d", status, pid); + } + } + } +} + +static +int run_child(int argc, char **argv) +{ + pid_t pid; + int ret; + + if (argc < 1) { + ERR("Please provide executable name as first argument."); + return -1; + } + + pid = fork(); + if (pid > 0) { + /* In parent */ + DBG("Child process created (pid: %d)", pid); + } else if (pid == 0) { + /* In child */ +#if 0 + long ptraceret; + + ptraceret = ptrace(PTRACE_TRACEME, 0, NULL, NULL); + if (ptraceret) { + PERROR("ptrace"); + exit(EXIT_FAILURE); + } +#endif + ret = raise(SIGSTOP); + if (ret) { + PERROR("raise"); + exit(EXIT_FAILURE); + } + ret = execvp(argv[0], &argv[0]); + if (ret) { + PERROR("execvp"); + exit(EXIT_FAILURE); + } + } else { + PERROR("fork"); + return -1; + } + return pid; +} + +static +int create_session(struct lttng_trace_ctx *ctx) +{ + return lttng_create_session(ctx->session_name, ctx->path); +} + +static +int destroy_session(struct lttng_trace_ctx *ctx) +{ + return lttng_destroy_session(ctx->session_name); +} + +static +int start_session(struct lttng_trace_ctx *ctx) +{ + return lttng_start_tracing(ctx->session_name); +} + +static +int enable_syscalls(struct lttng_trace_ctx *ctx) +{ + struct lttng_domain domain; + struct lttng_event *ev; + struct lttng_handle *handle; + int ret; + + if (opt_no_syscall) + return 0; + memset(&domain, 0, sizeof(domain)); + ev = lttng_event_create(); + if (!ev) + abort(); + domain.type = LTTNG_DOMAIN_KERNEL; + domain.buf_type = LTTNG_BUFFER_GLOBAL; + + handle = lttng_create_handle(ctx->session_name, &domain); + if (!handle) + abort(); + ev->type = LTTNG_EVENT_SYSCALL; + strcpy(ev->name, "*"); + ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; + ret = lttng_enable_event_with_exclusions(handle, + ev, NULL, NULL, 0, NULL); + if (ret) + abort(); + lttng_destroy_handle(handle); + return 0; +} + +static +int add_contexts(struct lttng_trace_ctx *ctx, enum lttng_domain_type domain_type) +{ + struct lttng_domain domain; + struct lttng_event_context event_ctx; + struct lttng_handle *handle; + + if (opt_no_context) + return 0; + memset(&domain, 0, sizeof(domain)); + switch (domain_type) { + case LTTNG_DOMAIN_KERNEL: + domain.buf_type = LTTNG_BUFFER_GLOBAL; + break; + case LTTNG_DOMAIN_UST: + domain.buf_type = LTTNG_BUFFER_PER_UID; + break; + default: + return -1; + } + domain.type = domain_type; + + handle = lttng_create_handle(ctx->session_name, &domain); + if (!handle) + abort(); + + memset(&event_ctx, 0, sizeof(event_ctx)); + event_ctx.ctx = LTTNG_EVENT_CONTEXT_PROCNAME; + if (lttng_add_context(handle, &event_ctx, NULL, NULL) < 0) + abort(); + + memset(&event_ctx, 0, sizeof(event_ctx)); + event_ctx.ctx = LTTNG_EVENT_CONTEXT_VPID; + if (lttng_add_context(handle, &event_ctx, NULL, NULL) < 0) + abort(); + + memset(&event_ctx, 0, sizeof(event_ctx)); + event_ctx.ctx = LTTNG_EVENT_CONTEXT_VTID; + if (lttng_add_context(handle, &event_ctx, NULL, NULL) < 0) + abort(); + + lttng_destroy_handle(handle); + return 0; +} + +static +int create_channels(struct lttng_trace_ctx *ctx, enum lttng_domain_type domain_type) +{ + struct lttng_domain domain; + struct lttng_channel *channel; + struct lttng_handle *handle; + + memset(&domain, 0, sizeof(domain)); + switch (domain_type) { + case LTTNG_DOMAIN_KERNEL: + domain.buf_type = LTTNG_BUFFER_GLOBAL; + break; + case LTTNG_DOMAIN_UST: + domain.buf_type = LTTNG_BUFFER_PER_UID; + break; + default: + return -1; + } + domain.type = domain_type; + channel = lttng_channel_create(&domain); + channel->enabled = 1; + + handle = lttng_create_handle(ctx->session_name, &domain); + if (!handle) + abort(); + if (lttng_enable_channel(handle, channel) < 0) + abort(); + lttng_destroy_handle(handle); + + lttng_channel_destroy(channel); + return 0; +} + +static +struct lttng_handle *create_kernel_handle(struct lttng_trace_ctx *ctx) +{ + struct lttng_domain domain; + + memset(&domain, 0, sizeof(domain)); + domain.type = LTTNG_DOMAIN_KERNEL; + domain.buf_type = LTTNG_BUFFER_GLOBAL; + return lttng_create_handle(ctx->session_name, &domain); +} + +static +struct lttng_handle *create_ust_handle(struct lttng_trace_ctx *ctx) +{ + struct lttng_domain domain; + + memset(&domain, 0, sizeof(domain)); + domain.type = LTTNG_DOMAIN_UST; + domain.buf_type = LTTNG_BUFFER_PER_UID; + return lttng_create_handle(ctx->session_name, &domain); +} + +static +void sighandler(int signo, siginfo_t *siginfo __unused, void *context __unused) +{ + int ret; + + DBG("sighandler receives signal %d, forwarding to child %d", + signo, sigfwd_pid); + ret = kill(sigfwd_pid, signo); + if (ret) { + PERROR("kill"); + abort(); + } +} + +static +int lttng_trace_ctx_init(struct lttng_trace_ctx *ctx) +{ + pid_t pid; + char pid_str[12]; + int ret; + char datetime[16]; + struct tm *timeinfo; + + ctx->creation_time = time(NULL); + if (ctx->creation_time == (time_t) -1) + abort(); + timeinfo = localtime(&ctx->creation_time); + if (!timeinfo) + abort(); + strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo); + + if (opt_session) { + if (strlen(session_name) > LTTNG_NAME_MAX - 1) { + abort(); + } + strcpy(ctx->session_name, session_name); + } else { + memset(ctx, 0, sizeof(*ctx)); + strcpy(ctx->session_name, "lttng-ptrace-"); + pid = getpid(); + ret = sprintf(pid_str, "%d", (int) pid); + if (ret < 0) + return -1; + strcat(ctx->session_name, pid_str); + strcat(ctx->session_name, "-"); + strcat(ctx->session_name, datetime); + } + + if (opt_output) { + if (strlen(output_path) > PATH_MAX - 1) { + abort(); + } + strcpy(ctx->path, output_path); + } else { + strcpy(ctx->path, "/tmp/lttng-ptrace/"); + strcat(ctx->path, ctx->session_name); + } + return 0; +} + +static +int lttng_trace_untrack_all(struct lttng_handle **handle, + size_t nr_handles) +{ + size_t i; + int ret; + + for (i = 0; i < nr_handles; i++) { + ret = lttng_untrack_pid(handle[i], -1); + if (ret && ret != -LTTNG_ERR_INVALID) { + ERR("Error %d untracking pid %d", ret, -1); + abort(); + } + } + return 0; +} + +/* Return value: + * >= 0: number of arguments to skip before command. + * < 0: error. + */ +static +int parse_args(int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) { + const char *str = argv[i]; + + if (!strcmp(str, "--")) { + i++; /* Next is command position. */ + goto end; + } + if (str[0] != '-') { + goto end; /* Cursor at command position. */ + } + if (!strcmp(str, "--help")) { + opt_help = true; + } + if (!strcmp(str, "--no-context")) { + opt_no_context = true; + } + if (!strcmp(str, "--no-pause")) { + opt_no_pause = true; + } + if (!strcmp(str, "--no-syscall")) { + opt_no_syscall = true; + } + if (!strcmp(str, "--output")) { + opt_output = true; + if (i == argc - 1) { + ERR("Expected path argument after --output"); + return -1; + } + output_path = argv[++i]; + } + if (!strcmp(str, "--session")) { + opt_session = true; + if (i == argc - 1) { + ERR("Expected path argument after --session"); + return -1; + } + session_name = argv[++i]; + } + if (!strcmp(str, "--view")) { + opt_view = true; + } + } +end: + if (i == argc && !opt_help) { + ERR("Expected COMMAND argument after options. See `%s --help` for details.", argv[0]); + return -1; + } + return i; +} + +static +int show_help(int argc __unused, char **argv) +{ + printf("Usage of %s:\n", argv[0]); + printf("\n"); + printf(" %s [OPTION] [--] COMMAND [COMMAND OPTIONS]\n", argv[0]); + printf("\n"); + printf("Runs COMMAND while tracing the system calls of the children\n"); + printf("process hierarchy. See standard error output while executing\n"); + printf("this command for more information.\n"); + printf("\n"); + printf("Supported options:\n"); + printf(" --help: This help screen.\n"); + printf(" --no-context: Do not trace default contexts (vpid, vtid, procname).\n"); + printf(" --no-pause: Do not wait for user input before running COMMAND.\n"); + printf(" --no-syscall: Do not trace system calls.\n"); + printf(" --output PATH: Write trace into output PATH. (default: /tmp/lttng-ptrace/$SESSION_NAME)\n"); + printf(" --session NAME: Tracing session name. (default: lttng-ptrace-$PID-$DATETIME)\n"); + printf(" --view: View trace after end of COMMAND execution.\n"); + printf("\n"); + return 0; +} + +int main(int argc, char **argv) +{ + int retval = 0, ret; + pid_t pid; + struct lttng_handle *handle[NR_HANDLES]; + struct sigaction act; + struct lttng_trace_ctx ptrace_ctx; + int skip_args = 0; + + skip_args = parse_args(argc, argv); + if (skip_args < 0) { + return EXIT_FAILURE; + } + if (opt_help) { + show_help(argc, argv); + return EXIT_SUCCESS; + } + + if (lttng_trace_ctx_init(&ptrace_ctx)) + abort(); + + act.sa_sigaction = sighandler; + act.sa_flags = SA_SIGINFO | SA_RESTART; + sigemptyset(&act.sa_mask); + ret = sigaction(SIGTERM, &act, NULL); + if (ret) + abort(); + ret = sigaction(SIGINT, &act, NULL); + if (ret) + abort(); + + if (create_session(&ptrace_ctx) < 0) { + fprintf(stderr, "%sError: Unable to create tracing session. Please ensure that lttng-sessiond is running as root and that your user belongs to the `tracing` group.\n", MESSAGE_PREFIX); + retval = -1; + goto end; + } + handle[0] = create_kernel_handle(&ptrace_ctx); + if (!handle[0]) { + retval = -1; + goto end_kernel_handle; + } + handle[1] = create_ust_handle(&ptrace_ctx); + if (!handle[1]) { + retval = -1; + goto end_ust_handle; + } + if (create_channels(&ptrace_ctx, LTTNG_DOMAIN_KERNEL) < 0) { + retval = -1; + goto end_wait_on_children; + } + if (create_channels(&ptrace_ctx, LTTNG_DOMAIN_UST) < 0) { + retval = -1; + goto end_wait_on_children; + } + if (enable_syscalls(&ptrace_ctx) < 0) { + retval = -1; + goto end_wait_on_children; + } + if (add_contexts(&ptrace_ctx, LTTNG_DOMAIN_KERNEL) < 0) { + retval = -1; + goto end_wait_on_children; + } + if (add_contexts(&ptrace_ctx, LTTNG_DOMAIN_UST) < 0) { + retval = -1; + goto end_wait_on_children; + } + if (lttng_trace_untrack_all(handle, NR_HANDLES) < 0) { + retval = -1; + goto end_wait_on_children; + } + fprintf(stderr, "%sTracing session `%s` created. It can be customized using the `lttng` command.\n", MESSAGE_PREFIX, ptrace_ctx.session_name); + if (!opt_no_pause) { + fprintf(stderr, "Press key when ready to run the child process.\n"); + getchar(); + } + + if (start_session(&ptrace_ctx) < 0) { + retval = -1; + goto end_wait_on_children; + } + + //TODO: signal off before we can forward it. + pid = run_child(argc - skip_args, argv + skip_args); + if (pid <= 0) { + retval = -1; + goto end; + } + + sigfwd_pid = pid; + //TODO signals on + + ret = wait_on_children(pid, handle, NR_HANDLES); + if (ret) { + retval = -1; + goto end_wait_on_children; + } + + +end_wait_on_children: + lttng_destroy_handle(handle[1]); +end_ust_handle: + lttng_destroy_handle(handle[0]); +end_kernel_handle: + if (destroy_session(&ptrace_ctx)) + abort(); +end: + if (retval) { + return EXIT_FAILURE; + } else { + fprintf(stderr, "%sSub-process hierarchy traced successfully. View trace with `babeltrace2 %s`.\n", MESSAGE_PREFIX, + ptrace_ctx.path); + if (opt_view) { + return execlp("babeltrace2", "babeltrace2", ptrace_ctx.path, NULL); + } + return EXIT_SUCCESS; + } + return 0; +} -- 2.34.1