summaryrefslogtreecommitdiff
path: root/cmake/dtrace.cmake
blob: dae3b56b584b97b53411e2a97e777aa172ddf4aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
# 
# 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; version 2 of the License.
#
# 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-1335  USA 

IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_COMPILER_IS_GNUCXX
  AND CMAKE_SIZEOF_VOID_P EQUAL 4)
  IF(NOT DEFINED BUGGY_GCC_NO_DTRACE_MODULES)
    EXECUTE_PROCESS(
      COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}  --version
      OUTPUT_VARIABLE out)
    IF(out MATCHES "3.4.6")
     # This gcc causes crashes in dlopen() for dtraced shared libs,
     # while standard shipped with Solaris10 3.4.3 is ok
     SET(BUGGY_GCC_NO_DTRACE_MODULES 1 CACHE INTERNAL "")
    ELSE()
     SET(BUGGY_GCC_NO_DTRACE_MODULES 0 CACHE INTERNAL "")
    ENDIF()
  ENDIF()
ENDIF()

# Check if OS supports DTrace
MACRO(CHECK_DTRACE)
 FIND_PROGRAM(DTRACE dtrace)
 MARK_AS_ADVANCED(DTRACE)

 IF(CMAKE_C_COMPILER MATCHES "ccache" AND CMAKE_SYSTEM_NAME MATCHES "Linux")
   # dtrace fails on fedora if  CC='ccache gcc' is used
   SET(BUGGY_LINUX_DTRACE 1)
 ENDIF()

 # On FreeBSD, dtrace does not handle userland tracing yet
 IF(DTRACE AND NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD"
     AND NOT BUGGY_GCC_NO_DTRACE_MODULES
     AND NOT BUGGY_LINUX_DTRACE
     AND NOT CMAKE_SYSTEM_NAME MATCHES "SunOS"
     AND NOT WIN32)
   SET(ENABLE_DTRACE ON CACHE BOOL "Enable dtrace")
 ENDIF()
 # On GNU/Hurd, dtrace is not supported
 IF(DTRACE AND CMAKE_SYSTEM_NAME MATCHES "GNU")
   SET(ENABLE_DTRACE OFF CACHE BOOL "Disable dtrace")
 ENDIF()
 SET(HAVE_DTRACE ${ENABLE_DTRACE})
 IF(CMAKE_SYSTEM_NAME MATCHES "SunOS")
   IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
     SET(DTRACE_FLAGS -32 CACHE INTERNAL "DTrace architecture flags")
   ELSE()
     SET(DTRACE_FLAGS -64 CACHE INTERNAL "DTrace architecture flags")
   ENDIF()
 ENDIF()
ENDMACRO()

CHECK_DTRACE()

# Produce a header file  with
# DTrace macros
MACRO (DTRACE_HEADER provider header header_no_dtrace)
 IF(ENABLE_DTRACE)
 ADD_CUSTOM_COMMAND(
   OUTPUT  ${header} ${header_no_dtrace}
   COMMAND ${DTRACE} -h -s ${provider} -o ${header}
   COMMAND perl ${CMAKE_SOURCE_DIR}/scripts/dheadgen.pl -f ${provider} > ${header_no_dtrace}
   DEPENDS ${provider}
 )
 ENDIF()
ENDMACRO()


# Create provider headers
IF(ENABLE_DTRACE)
  CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/include/probes_mysql.d.base 
    ${CMAKE_BINARY_DIR}/include/probes_mysql.d COPYONLY)
  DTRACE_HEADER(
   ${CMAKE_BINARY_DIR}/include/probes_mysql.d 
   ${CMAKE_BINARY_DIR}/include/probes_mysql_dtrace.h
   ${CMAKE_BINARY_DIR}/include/probes_mysql_nodtrace.h
  )
  ADD_CUSTOM_TARGET(gen_dtrace_header
  DEPENDS  
  ${CMAKE_BINARY_DIR}/include/probes_mysql.d
  ${CMAKE_BINARY_DIR}/include/probes_mysql_dtrace.h
  ${CMAKE_BINARY_DIR}/include/probes_mysql_nodtrace.h
  ) 
ELSE()
 CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/include/probes_mysql_nodtrace.h.in
   ${CMAKE_BINARY_DIR}/include/probes_mysql_nodtrace.h COPYONLY)
ENDIF()

FUNCTION(DTRACE_INSTRUMENT target)
  IF(BUGGY_GCC_NO_DTRACE_MODULES)
    GET_TARGET_PROPERTY(target_type ${target} TYPE)
    IF(target_type MATCHES "MODULE_LIBRARY")
      RETURN()
    ENDIF()
  ENDIF()
  IF(ENABLE_DTRACE)
    ADD_DEPENDENCIES(${target} gen_dtrace_header)

    # Invoke dtrace to generate object file and link it together with target.
    IF(CMAKE_SYSTEM_NAME MATCHES "SunOS")
      SET(objdir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir)
      SET(outfile ${objdir}/${target}_dtrace.o)
      GET_TARGET_PROPERTY(target_type ${target} TYPE)
      ADD_CUSTOM_COMMAND(
        TARGET ${target} PRE_LINK 
        COMMAND ${CMAKE_COMMAND}
          -DDTRACE=${DTRACE}	  
          -DOUTFILE=${outfile} 
          -DDFILE=${CMAKE_BINARY_DIR}/include/probes_mysql.d
          -DDTRACE_FLAGS=${DTRACE_FLAGS}
          -DDIRS=.
          -DTYPE=${target_type}
          -P ${CMAKE_SOURCE_DIR}/cmake/dtrace_prelink.cmake
        WORKING_DIRECTORY ${objdir}
      )
    ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Linux")
      # dtrace on Linux runs gcc and uses flags from environment
      SET(CFLAGS_SAVED $ENV{CFLAGS})
      SET(ENV{CFLAGS} ${CMAKE_C_FLAGS})
      SET(outfile "${CMAKE_BINARY_DIR}/probes_mysql.o")
      # Systemtap object
      EXECUTE_PROCESS(
        COMMAND ${DTRACE} -G -s ${CMAKE_SOURCE_DIR}/include/probes_mysql.d.base
        -o ${outfile}
        )
      SET(ENV{CFLAGS} ${CFLAGS_SAVED})
    ENDIF()

    # Do not try to extend the library if we have not built the .o file
    IF(outfile)
      # Add full  object path to linker flags
      GET_TARGET_PROPERTY(target_type ${target} TYPE)
      IF(NOT target_type MATCHES "STATIC")
        SET_TARGET_PROPERTIES(${target} PROPERTIES LINK_FLAGS "${outfile}")
      ELSE()
        # For static library flags, add the object to the library.
        # Note: DTrace probes in static libraries are  unusable currently 
        # (see explanation for DTRACE_INSTRUMENT_STATIC_LIBS below)
        # but maybe one day this will be fixed.
        ADD_CUSTOM_COMMAND(
          TARGET ${target} POST_BUILD
          COMMAND ${CMAKE_AR} r  $<TARGET_FILE:${target}> ${outfile}
          COMMAND ${CMAKE_RANLIB} $<TARGET_FILE:${target}>
          )
        # Used in DTRACE_INSTRUMENT_WITH_STATIC_LIBS
        SET(TARGET_OBJECT_DIRECTORY_${target}  ${objdir} CACHE INTERNAL "")
      ENDIF()
    ENDIF()
  ENDIF()
ENDFUNCTION()


# Ugly workaround for Solaris' DTrace inability to use probes
# from static libraries, discussed e.g in this thread
# (http://opensolaris.org/jive/thread.jspa?messageID=432454)
# We have to collect all object files that may be instrumented
# and go into the mysqld (also those that come from in static libs)
# run them again through dtrace -G to generate an ELF file that links
# to mysqld.
MACRO (DTRACE_INSTRUMENT_STATIC_LIBS target libs)
IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND ENABLE_DTRACE)
  # Filter out non-static libraries in the list, if any
  SET(static_libs)
  FOREACH(lib ${libs})
    GET_TARGET_PROPERTY(libtype ${lib} TYPE)
    IF(libtype MATCHES STATIC_LIBRARY)
      SET(static_libs ${static_libs} ${lib})
    ENDIF()
  ENDFOREACH()

  FOREACH(lib ${static_libs})
    SET(dirs ${dirs} ${TARGET_OBJECT_DIRECTORY_${lib}})
  ENDFOREACH()

  SET (obj ${CMAKE_CURRENT_BINARY_DIR}/${target}_dtrace_all.o)
  ADD_CUSTOM_COMMAND(
  OUTPUT ${obj}
  DEPENDS ${static_libs}
  COMMAND ${CMAKE_COMMAND}
   -DDTRACE=${DTRACE}	  
   -DOUTFILE=${obj} 
   -DDFILE=${CMAKE_BINARY_DIR}/include/probes_mysql.d
   -DDTRACE_FLAGS=${DTRACE_FLAGS}
   "-DDIRS=${dirs}"
   -DTYPE=MERGE
   -P ${CMAKE_SOURCE_DIR}/cmake/dtrace_prelink.cmake
   VERBATIM
  )
  ADD_CUSTOM_TARGET(${target}_dtrace_all  DEPENDS ${obj})
  ADD_DEPENDENCIES(${target} ${target}_dtrace_all)
  TARGET_LINK_LIBRARIES(${target} ${obj})
ENDIF()
ENDMACRO()