[lttng-dev] instrumenting shared library
Lingyu Zhu
lynuszhu at gmail.com
Sat Apr 5 02:44:50 EDT 2014
If you omit defining the macro TRACEPOINT_PROBE_DYNAMIC_LINKAGE in your
library which you want to trace, your library will depend on the trace
provider shared library. And you will not bother LD_PRELOAD your tracepoint
provider library before launching app.
However, by doing so you will lose control over switching on or off
'tracing mode': whenever your code is called,your tracepoint will try to
register and tracepoint() might have more overhead if you build your
library like that, whereas your tracepoint won't register and tracepoint()
macro just cost a simple branch if you do so by normal way and skip
LD_PRELOAD.
On Sat, Apr 5, 2014 at 4:16 AM, Anand Neeli <anand.neeli at gmail.com> wrote:
> Hi Daniel,
> Thanks for your detailed mail.
> I will spend time with my code and get back if i have more queries.
>
> What i'm looking at it is: adding lttng infra in our code base. I'm
> looking for a solution where most of the lttng build and launch parts are
> abstracted to the end app/library developer.
> That is the reason why i'm not in favor of having LD_PRELOAD while
> launching an app. This would need the app developer to check if included
> libraries has tracing support and add .so appropriately to LD_PRELOAD
> (which needs more education to developer on lttng and included libraries)
> If we can launch app(with or without instrumented library) normally and
> limit the complexity of linking to makefile it will be great.
>
> Please keep me posted if you have any more thoughts on this.
> Also, can you please send me the users guide.
>
> Thanks,
> Anand Neeli
>
>
> On Fri, Apr 4, 2014 at 8:13 PM, Thibault, Daniel <
> Daniel.Thibault at drdc-rddc.gc.ca> wrote:
>
>> *De :* Anand Neeli [mailto:anand.neeli at gmail.com]
>> *Envoyé :* 4 avril 2014 01:45
>>
>> > Thanks for your reply.
>>
>> > Sorry for my ignorance but how are you generating libtp.so in your
>> example?
>>
>>
>>
>> Non-boilerplate parts are in red.
>>
>>
>>
>> tp.c:
>>
>> #####
>>
>> /*
>>
>> * Defining macro creates the code objects of the traceprobes.
>>
>> * Must be done only once per file (this #define controls tracepoint.h and
>>
>> * tracepoint-event.h).
>>
>> */
>>
>> #define TRACEPOINT_CREATE_PROBES
>>
>> /*
>>
>> * The header containing our TRACEPOINT_EVENTs.
>>
>> */
>>
>> #include "tp.h"
>>
>> #####
>>
>> tp.h:
>> #####
>> #undef TRACEPOINT_PROVIDER
>>
>> #define TRACEPOINT_PROVIDER sample_component
>>
>> /*
>>
>> * include file (this files's name)
>>
>> */
>>
>> #undef TRACEPOINT_INCLUDE
>>
>> #define TRACEPOINT_INCLUDE "./tp.h"
>>
>> /*
>>
>> * Add this precompiler conditional to ensure the tracepoint event
>> generation
>>
>> * can include this file more than once.
>>
>> */
>>
>> #if !defined(_SAMPLE_COMPONENT_PROVIDER_H) ||
>> defined(TRACEPOINT_HEADER_MULTI_READ)
>>
>> #define _SAMPLE_COMPONENT_PROVIDER_H
>>
>> /*
>>
>> * Add this to allow programs to call "tracepoint(...)".
>>
>> * This #include must not be within an extern "C" block; if it is,
>>
>> * C++ instrumentation will fail when SystemTap is also installed.
>>
>> * (This may have been fixed since I wrote this)
>>
>> */
>>
>> #include <lttng/tracepoint.h>
>>
>> /*
>>
>> * Add this macro and its matching element to make sure the program
>>
>> * works in C++.
>>
>> */
>>
>> #ifdef __cplusplus
>>
>> extern "C" {
>>
>> #endif /* __cplusplus */
>>
>>
>>
>> /*
>>
>> * The following tracepoint event writes a message (C string) into the
>>
>> * field "message" of the trace event "event" in the provider
>>
>> * "sample_component" in other words:
>>
>> *
>>
>> * sample_component:event:message = text.
>>
>> */
>>
>> TRACEPOINT_EVENT(
>>
>> /*
>>
>> * provider name, not a variable but a string starting with a
>> letter
>>
>> * and containing either letters, numbers or underscores.
>>
>> * Needs to be the same as TRACEPOINT_PROVIDER
>>
>> */
>>
>> sample_component,
>>
>> /*
>>
>> * tracepoint name, same format as sample provider. Does not
>> need to be
>>
>> * declared before. in this case the name is "event"
>>
>> */
>>
>> event,
>>
>> /*
>>
>> * TP_ARGS macro contains the arguments passed for the
>> tracepoint.
>>
>> * It is in the following format:
>>
>> * TP_ARGS( type1, name1, type2, name2,
>> ... type10, name10)
>>
>> * where there can be from zero to ten elements.
>>
>> * "typeN" is the datatype, such as int, struct or double **.
>>
>> * "name" is the variable name (in "int myInt" the name would
>> be "myInt")
>>
>> * TP_ARGS() is valid (no arguments)
>>
>> * TP_ARGS( void ) is valid too
>>
>> */
>>
>> TP_ARGS(const char *, text),
>>
>> /*
>>
>> * TP_FIELDS describes how to write the fields of the trace
>> event.
>>
>> * You can use the args here
>>
>> */
>>
>> TP_FIELDS(
>>
>> /*
>>
>> * The ctf_string macro takes a C string and writes it into a
>> field
>>
>> * named "message"
>>
>> */
>>
>> ctf_string(message, text)
>>
>> )
>>
>> )
>>
>> /*
>>
>> * Trace loglevel, shows the level of the trace event. It can be
>> TRACE_EMERG,
>>
>> * TRACE_ALERT, TRACE_CRIT, TRACE_ERR, TRACE_WARNING, TRACE_INFO, etc.
>>
>> * If this is not set, TRACE_DEFAULT is assumed.
>>
>> * The first two arguments identify the tracepoint.
>>
>> * See details in <lttng/tracepoint.h> line 347
>>
>> */
>>
>> TRACEPOINT_LOGLEVEL(
>>
>> /*
>>
>> * The provider name, must be the same as the provider name in the
>>
>> * TRACEPOINT_EVENT and as TRACEPOINT_PROVIDER above.
>>
>> */
>>
>> sample_component,
>>
>> /*
>>
>> * The tracepoint name, must be the same as the tracepoint name in
>> the
>>
>> * TRACEPOINT_EVENT
>>
>> */
>>
>> event,
>>
>> /*
>>
>> * The tracepoint loglevel. WARNING: Some levels are abbreviated
>> and
>>
>> * others are not, please see <lttng/tracepoint.h>
>>
>> */
>>
>> TRACE_WARNING
>>
>> )
>>
>> (more tracepoints…)
>>
>>
>>
>> /*
>>
>> * Add this macro and its matching element to make sure the program
>>
>> * works in C++.
>>
>> */
>>
>> #ifdef __cplusplus
>>
>> }
>>
>> #endif /* __cplusplus */
>>
>> /*
>>
>> * Add this after defining the tracepoint events to expand the macros.
>>
>> */
>>
>> #include <lttng/tracepoint-event.h>
>>
>> #endif /* _SAMPLE_COMPONENT_PROVIDER_H */
>>
>> #####
>>
>> The relevant Makefile fragments:
>> #####
>> CC = gcc
>> LIBUST = -llttng-ust
>>
>> LOCAL_CPPFLAGS += -I. $(AM_CPPFLAGS)
>> LDFLAGS += -L/usr/local/lib $(AM_LDFLAGS)
>> SOFLAGS = -fPIC
>> SOVERSION_MAJOR = 1
>> SOVERSION_MINOR = 0
>>
>> libtp.so: libtp.o
>>
>> @echo "~~~~~~Packaging $@:"
>>
>> $(CC) -shared -Wl,-soname,$@.$(SOVERSION_MAJOR)
>> -Wl,-no-as-needed \
>>
>> -o $@.$(SOVERSION_MAJOR).$(SOVERSION_MINOR) $(LDFLAGS)
>> $(LIBUST) $<
>>
>> ln -sf $@.$(SOVERSION_MAJOR).$(SOVERSION_MINOR)
>> $@.$(SOVERSION_MAJOR)
>>
>> ln -sf $@.$(SOVERSION_MAJOR) $@
>>
>>
>>
>> libtp.o: tp.c tp.h
>>
>> @echo "~~~~~~Compiling $@:"
>>
>> $(CC) $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(SOFLAGS) -c -o $@ $<
>>
>>
>> > 1) Also will this solution scale if my binary depends on lots
>> of libraries which are instrumented?
>>
>>
>>
>> Sure. I’d expect linear scaling. Each library, upon being loaded, looks
>> for its tracepoint provider and turns its tracepoints off if they’re not
>> found.
>>
>>
>>
>> > 2) i'm fine with linking statically, can we avoid LD_PRELOAD?
>>
>>
>>
>> Besides the LD_PRELOAD technique, you could also use LD_LIBRARY_PATH, but
>> that works only if the application statically includes the tracepoint
>> provider (I suppose it would likewise work for an instrumented shared
>> object only if it statically includes the tracepoint provider).
>>
>>
>>
>> You could also add "-Wl,-rpath,'$$ORIGIN'" to the linker call to add an
>> RPATH tag to the application (or shared object). This makes it look for
>> its dependencies in its starting directory ($ORIGIN). RPATH is, unlike
>> RUNPATH, applicable to libraries as well: a library with an RPATH tag will
>> look there for its dependencies; failing its own RPATH, it will use its
>> executable's RPATH.
>>
>>
>>
>> Finally, you can dynamically include the tracepoint provider (libtp) as a
>> dependency. The application (sample_static_aware) is then statically aware
>> of libtp and won't run without it. The application (sample_dynamic) can
>> alternately dynamically include the tracepoint provider *without* static
>> awareness. Here’s how it’s done:
>>
>>
>>
>> LIBDL = -ldl # On Linux
>>
>> #LIBDL = -lc # On BSD
>>
>> TP_DEFINE = -D TRACEPOINT_DEFINE
>>
>> TP_DEFINE_DYNAMIC = $(TP_DEFINE) -D TRACEPOINT_PROBE_DYNAMIC_LINKAGE
>>
>>
>>
>> #(the inclusion of a libtp NEEDED tag requires "-no-as-needed -ltp").
>>
>> #Note that "-L. -ltp", when used, should appear before $(LDFLAGS)
>> $(LIBDL).
>>
>> static_aware: static.o libtp.so
>>
>> @echo "~~~~~~Linking sample_$@:"
>>
>> # $(CC) -Wl,-no-as-needed -o sample_$@ -L. -ltp $< $(LDFLAGS)
>> $(LIBDL) \
>>
>> # -Wl,-rpath,'$$ORIGIN',--enable-new-dtags
>>
>> $(CC) -Wl,-no-as-needed -o sample_$@ -L. -ltp $< $(LDFLAGS)
>> $(LIBDL)
>>
>> @echo " Use 'LD_PRELOAD=./libtp.so ./sample_$@' to run
>> sample_$@"
>>
>>
>>
>> static.o: sample.c tp.h
>>
>> @echo "~~~~~~Compiling $@:"
>>
>> $(CC) $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(TP_DEFINE) -c -o $@ $<
>>
>>
>>
>> #If not preloaded, the sample application runs but won't be traceable.
>>
>> #Putting libtp in the path won't work: the sample does not look for it.
>>
>> dynamic: dynamic.o libtp.so
>>
>> @echo "~~~~~~Linking sample_$@:"
>>
>> $(CC) -o sample_$@ $< $(LDFLAGS) $(LIBDL)
>>
>> @echo " Use '[LD_PRELOAD=./libtp.so] ./sample_$@' to run
>> sample_$@"
>>
>>
>>
>> #Compare with the 'static.o' target.
>>
>> dynamic.o: sample.c tp.h
>>
>> @echo "~~~~~~Compiling $@:"
>>
>> $(CC) $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(TP_DEFINE_DYNAMIC) \
>>
>> -c -o $@ $<
>>
>>
>>
>> The case where the app isn’t traced but the library it uses is traced
>> should be a variation on this. I’ll try it out sometime in the near
>> future, but you should be able to figure it out from the above. Here’s a
>> first guess (it may need $(LIBDL) alongside $(LIBUST)):
>>
>>
>>
>> libtp.so: libtp.o
>>
>> @echo "~~~~~~Packaging $@:"
>>
>> $(CC) -shared -Wl,-soname,$@.$(SOVERSION_MAJOR)
>> -Wl,-no-as-needed -L. -ltp \
>>
>> -o $@.$(SOVERSION_MAJOR).$(SOVERSION_MINOR) $(LDFLAGS)
>> $(LIBUST) $<
>>
>> ln -sf $@.$(SOVERSION_MAJOR).$(SOVERSION_MINOR)
>> $@.$(SOVERSION_MAJOR)
>>
>> ln -sf $@.$(SOVERSION_MAJOR) $@
>>
>>
>>
>>
>>
>> > 3) Is there any page which explains on why and how to use
>>
>> > TRACEPOINT_PROVIDER, TRACEPOINT_CREATE_PROBES, TRACEPOINT_INCLUDE,
>> TRACEPOINT_DEFINE, TRACEPOINT_PROBE_DYNAMIC_LINKAGE
>>
>>
>>
>> They’re reasonably explained in the demonstration apps. I discuss them a
>> little more in depth in the forthcoming LTTng Comprehensive User’s Guide (I
>> could send you a copy of the draft, as we’ve just begun its first review
>> round).
>>
>>
>>
>> > my tp.h is, are there any errors in this?
>>
>> > #############
>>
>>
>>
>> #undef TRACEPOINT_PROVIDER
>>
>>
>>
>> > #define TRACEPOINT_PROVIDER sample_component
>>
>> >
>>
>> > #undef TRACEPOINT_INCLUDE
>>
>> > #define TRACEPOINT_INCLUDE "./tp.h"
>>
>> >
>>
>> > #if !defined(_TP_H) || defined(TRACEPOINT_HEADER_MULTI_READ)
>>
>> > #define _TP_H
>>
>>
>>
>> (Ideally, use _SAMPLE_COMPONENT_PROVIDER_H instead of _TP_H)
>>
>>
>>
>> > #include <lttng/tracepoint.h>
>>
>>
>>
>> #ifdef __cplusplus
>>
>> extern "C" {
>>
>> #endif /* __cplusplus */
>>
>>
>>
>> > TRACEPOINT_EVENT(
>>
>> > sample_component,
>>
>> > event,
>>
>> > TP_ARGS(char *, text),
>>
>>
>>
>> (the compiler may be happier with const char * instead)
>>
>>
>>
>> > TP_FIELDS(
>>
>> > ctf_string(message, text)
>>
>> > )
>>
>> >)
>>
>> > TRACEPOINT_LOGLEVEL(
>>
>> > sample_component,
>>
>> > event,
>>
>> > TRACE_WARNING)
>>
>>
>>
>> #ifdef __cplusplus
>>
>> }
>>
>> #endif /* __cplusplus */
>>
>>
>>
>> > #endif /* _TP_H */
>>
>> > #include <lttng/tracepoint-event.h>
>>
>>
>>
>> (move #include <lttng/tracepoint-event.h> inside of the #if
>> !defined(_TP_H) || defined(TRACEPOINT_HEADER_MULTI_READ))
>>
>>
>>
>> > #############
>>
>> >
>>
>> > Thanks,
>>
>> > Anand Neeli
>>
>>
>>
>> One key change I made to my sample applications is to remove the
>> “#define TRACEPOINT_DEFINE” that precedes the “#include "tp.h"” line. I
>> prefer to control that #define using a compiler -D option. It makes the
>> makefile clearer and resolves the problem of making sure there is just one
>> module that turns that #define on.
>>
>>
>>
>> Hope this helps.
>>
>>
>>
>> Daniel U. Thibault
>> Protection des systèmes et contremesures (PSC) | Systems Protection &
>> Countermeasures (SPC)
>> Cyber sécurité pour les missions essentielles (CME) | Mission Critical
>> Cyber Security (MCCS)
>> R & D pour la défense Canada - Valcartier (RDDC Valcartier) | Defence R&D
>> Canada - Valcartier (DRDC Valcartier)
>> 2459 route de la Bravoure
>> Québec QC G3J 1X5
>> CANADA
>> Vox : (418) 844-4000 x4245
>> Fax : (418) 844-4538
>> NAC : 918V QSDJ <http://www.travelgis.com/map.asp?addr=918V%20QSDJ<http://--ESFSECEV-TY3011-------------------------------->
>> >
>> Gouvernement du Canada | Government of Canada
>> <http://www.valcartier.drdc-rddc.gc.ca/<http://--ESFSECEV-TY3011--------------------->
>> >
>>
>
>
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lttng.org/pipermail/lttng-dev/attachments/20140405/10dd219c/attachment-0001.html>
More information about the lttng-dev
mailing list