1# Copyright (c) 2009, 2021, Oracle and/or its affiliates.
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License, version 2.0,
5# as published by the Free Software Foundation.
6#
7# This program is also distributed with certain software (including
8# but not limited to OpenSSL) that is licensed under separate terms,
9# as designated in a particular file or component or in included license
10# documentation.  The authors of MySQL hereby grant you an additional
11# permission to link the program and your derivative works with the
12# separately licensed software that they have included with MySQL.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License, version 2.0, for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22
23# Check if OS supports DTrace
24MACRO(CHECK_DTRACE)
25  IF(DEFINED ENABLE_DTRACE AND NOT ENABLE_DTRACE)
26    MESSAGE(STATUS "DTRACE is disabled")
27  ELSE()
28    FIND_PROGRAM(DTRACE dtrace)
29    MARK_AS_ADVANCED(DTRACE)
30
31    IF(DTRACE)
32      EXECUTE_PROCESS(
33        COMMAND ${DTRACE} -V
34        OUTPUT_VARIABLE out)
35      IF(out MATCHES "Sun D" OR out MATCHES "Oracle D")
36        IF(NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD" AND
37            NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
38          SET(HAVE_REAL_DTRACE_INSTRUMENTING ON CACHE BOOL "Real DTrace detected")
39        ENDIF()
40      ENDIF()
41    ENDIF()
42
43    # On FreeBSD, dtrace does not handle userland tracing yet
44    IF(DTRACE AND NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
45      # We do not support DTrace 2.0 on Linux
46      IF(LINUX AND HAVE_REAL_DTRACE_INSTRUMENTING)
47        # Break the build if ENABLE_DTRACE set explicitly.
48        IF(DEFINED ENABLE_DTRACE AND ENABLE_DTRACE)
49          MESSAGE(FATAL_ERROR "Found unsupported dtrace at ${DTRACE}\n ${out}")
50        ELSE()
51          MESSAGE(WARNING "Found unsupported dtrace at ${DTRACE}\n ${out}")
52          SET(HAVE_REAL_DTRACE_INSTRUMENTING OFF CACHE BOOL "")
53          SET(ENABLE_DTRACE OFF CACHE BOOL "Enable dtrace")
54        ENDIF()
55      ELSE()
56        SET(ENABLE_DTRACE ON CACHE BOOL "Enable dtrace")
57        MESSAGE(STATUS "DTRACE is enabled")
58      ENDIF()
59    ENDIF()
60    SET(HAVE_DTRACE ${ENABLE_DTRACE})
61
62    IF(HAVE_REAL_DTRACE_INSTRUMENTING)
63      IF(SIZEOF_VOIDP EQUAL 4)
64        SET(DTRACE_FLAGS -32 CACHE INTERNAL "DTrace architecture flags")
65      ELSE()
66        SET(DTRACE_FLAGS -64 CACHE INTERNAL "DTrace architecture flags")
67      ENDIF()
68    ENDIF()
69
70  ENDIF()
71ENDMACRO()
72
73CHECK_DTRACE()
74
75# Produce a header file  with
76# DTrace macros
77MACRO (DTRACE_HEADER provider header header_no_dtrace)
78 IF(ENABLE_DTRACE)
79 ADD_CUSTOM_COMMAND(
80   OUTPUT  ${header} ${header_no_dtrace}
81   COMMAND ${DTRACE} -h -s ${provider} -o ${header}
82   COMMAND perl ${CMAKE_SOURCE_DIR}/scripts/dheadgen.pl -f ${provider} > ${header_no_dtrace}
83   DEPENDS ${provider}
84 )
85 ENDIF()
86ENDMACRO()
87
88
89# Create provider headers
90IF(ENABLE_DTRACE)
91  CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/include/probes_mysql.d.base
92    ${CMAKE_BINARY_DIR}/include/probes_mysql.d COPYONLY)
93  DTRACE_HEADER(
94   ${CMAKE_BINARY_DIR}/include/probes_mysql.d
95   ${CMAKE_BINARY_DIR}/include/probes_mysql_dtrace.h
96   ${CMAKE_BINARY_DIR}/include/probes_mysql_nodtrace.h
97  )
98  ADD_CUSTOM_TARGET(gen_dtrace_header
99  DEPENDS
100  ${CMAKE_BINARY_DIR}/include/probes_mysql.d
101  ${CMAKE_BINARY_DIR}/include/probes_mysql_dtrace.h
102  ${CMAKE_BINARY_DIR}/include/probes_mysql_nodtrace.h
103  )
104ENDIF()
105
106FUNCTION(DTRACE_INSTRUMENT target)
107  IF(ENABLE_DTRACE)
108    ADD_DEPENDENCIES(${target} gen_dtrace_header)
109
110    # Invoke dtrace to generate object file and link it together with target.
111    IF(HAVE_REAL_DTRACE_INSTRUMENTING)
112      SET(objdir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir)
113      SET(outfile ${objdir}/${target}_dtrace.o)
114      GET_TARGET_PROPERTY(target_type ${target} TYPE)
115      ADD_CUSTOM_COMMAND(
116        TARGET ${target} PRE_LINK
117        COMMAND ${CMAKE_COMMAND}
118          -DDTRACE=${DTRACE}
119          -DOUTFILE=${outfile}
120          -DDFILE=${CMAKE_BINARY_DIR}/include/probes_mysql.d
121          -DDTRACE_FLAGS=${DTRACE_FLAGS}
122          -DDIRS=.
123          -DTYPE=${target_type}
124          -P ${CMAKE_SOURCE_DIR}/cmake/dtrace_prelink.cmake
125        WORKING_DIRECTORY ${objdir}
126      )
127    ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Linux")
128      # dtrace on Linux runs gcc and uses flags from environment
129      SET(CFLAGS_SAVED $ENV{CFLAGS})
130      # We want to strip off all warning flags, including -Werror=xxx-xx,
131      # but keep flags like
132      #  -Wp,-D_FORTIFY_SOURCE=2
133      STRING(REGEX REPLACE "-W[A-Za-z0-9][-A-Za-z0-9=]+" ""
134        C_FLAGS "${CMAKE_C_FLAGS}")
135
136      SET(ENV{CFLAGS} ${C_FLAGS})
137      SET(outfile "${CMAKE_BINARY_DIR}/probes_mysql.o")
138      # Systemtap object
139      EXECUTE_PROCESS(
140        COMMAND ${DTRACE} -G -s ${CMAKE_SOURCE_DIR}/include/probes_mysql.d.base
141        -o ${outfile}
142        )
143      SET(ENV{CFLAGS} ${CFLAGS_SAVED})
144    ENDIF()
145
146    # Do not try to extend the library if we have not built the .o file
147    IF(outfile)
148      # Add full  object path to linker flags
149      GET_TARGET_PROPERTY(target_type ${target} TYPE)
150      IF(NOT target_type MATCHES "STATIC")
151        SET_TARGET_PROPERTIES(${target} PROPERTIES LINK_FLAGS "${outfile}")
152      ELSE()
153        # For static library flags, add the object to the library.
154        # Note: DTrace probes in static libraries are  unusable currently
155        # (see explanation for DTRACE_INSTRUMENT_STATIC_LIBS below)
156        # but maybe one day this will be fixed.
157        ADD_CUSTOM_COMMAND(
158          TARGET ${target} POST_BUILD
159          COMMAND ${CMAKE_AR} r $<TARGET_FILE:${target}> ${outfile}
160          COMMAND ${CMAKE_RANLIB} $<TARGET_FILE:${target}>
161          )
162        # Used in DTRACE_INSTRUMENT_WITH_STATIC_LIBS
163        SET(TARGET_OBJECT_DIRECTORY_${target}  ${objdir} CACHE INTERNAL "")
164      ENDIF()
165    ENDIF()
166  ENDIF()
167ENDFUNCTION()
168
169
170# Ugly workaround for Solaris' DTrace inability to use probes
171# from static libraries, discussed e.g in this thread
172# (http://opensolaris.org/jive/thread.jspa?messageID=432454)
173# We have to collect all object files that may be instrumented
174# and go into the mysqld (also those that come from in static libs)
175# run them again through dtrace -G to generate an ELF file that links
176# to mysqld.
177MACRO (DTRACE_INSTRUMENT_STATIC_LIBS target libs)
178IF(HAVE_REAL_DTRACE_INSTRUMENTING AND ENABLE_DTRACE)
179  # Filter out non-static libraries in the list, if any
180  SET(static_libs)
181  FOREACH(lib ${libs})
182    GET_TARGET_PROPERTY(libtype ${lib} TYPE)
183    IF(libtype MATCHES STATIC_LIBRARY)
184      SET(static_libs ${static_libs} ${lib})
185    ENDIF()
186  ENDFOREACH()
187
188  FOREACH(lib ${static_libs})
189    SET(dirs ${dirs} ${TARGET_OBJECT_DIRECTORY_${lib}})
190  ENDFOREACH()
191
192  SET (obj ${CMAKE_CURRENT_BINARY_DIR}/${target}_dtrace_all.o)
193  ADD_CUSTOM_COMMAND(
194  OUTPUT ${obj}
195  DEPENDS ${static_libs}
196  COMMAND ${CMAKE_COMMAND}
197   -DDTRACE=${DTRACE}
198   -DOUTFILE=${obj}
199   -DDFILE=${CMAKE_BINARY_DIR}/include/probes_mysql.d
200   -DDTRACE_FLAGS=${DTRACE_FLAGS}
201   "-DDIRS=${dirs}"
202   -DTYPE=MERGE
203   -P ${CMAKE_SOURCE_DIR}/cmake/dtrace_prelink.cmake
204   VERBATIM
205  )
206  ADD_CUSTOM_TARGET(${target}_dtrace_all  DEPENDS ${obj})
207  ADD_DEPENDENCIES(${target} ${target}_dtrace_all)
208  TARGET_LINK_LIBRARIES(${target} ${obj})
209ENDIF()
210ENDMACRO()
211