├── .gitignore ├── Documentation ├── .gitignore ├── Makefile ├── asciidoc.conf ├── install-docs.sh.in ├── libtracefs-cpu-buf.txt ├── libtracefs-cpu-map.txt ├── libtracefs-cpu-open.txt ├── libtracefs-cpu.txt ├── libtracefs-dynevents.txt ├── libtracefs-eprobes.txt ├── libtracefs-error.txt ├── libtracefs-events-file.txt ├── libtracefs-events-tep.txt ├── libtracefs-events.txt ├── libtracefs-files.txt ├── libtracefs-filter-pid.txt ├── libtracefs-filter.txt ├── libtracefs-function-filter.txt ├── libtracefs-guest.txt ├── libtracefs-hist-cont.txt ├── libtracefs-hist-mod.txt ├── libtracefs-hist.txt ├── libtracefs-instances-affinity.txt ├── libtracefs-instances-file-manip.txt ├── libtracefs-instances-files.txt ├── libtracefs-instances-manage.txt ├── libtracefs-instances-stat.txt ├── libtracefs-instances-subbuf.txt ├── libtracefs-instances-utils.txt ├── libtracefs-iterator.txt ├── libtracefs-kprobes.txt ├── libtracefs-log.txt ├── libtracefs-marker.txt ├── libtracefs-marker_raw.txt ├── libtracefs-option-get.txt ├── libtracefs-option-misc.txt ├── libtracefs-options.txt ├── libtracefs-snapshot.txt ├── libtracefs-sql.txt ├── libtracefs-sqlhist.txt.1 ├── libtracefs-stream.txt ├── libtracefs-synth-info.txt ├── libtracefs-synth.txt ├── libtracefs-synth2.txt ├── libtracefs-traceon.txt ├── libtracefs-tracer.txt ├── libtracefs-uprobes.txt ├── libtracefs-utils.txt ├── libtracefs.txt ├── manpage-1.72.xsl ├── manpage-base.xsl ├── manpage-bold-literal.xsl ├── manpage-normal.xsl ├── manpage-suppress-sp.xsl └── meson.build ├── LICENSES ├── GPL-2.0 └── LGPL-2.1 ├── Makefile ├── Makefile.meson ├── README ├── check-manpages.sh ├── include ├── meson.build ├── tracefs-local.h └── tracefs.h ├── libtracefs.pc.template ├── meson.build ├── meson_options.txt ├── samples ├── Makefile ├── cpu-map.c ├── extract-example.sh ├── meson.build └── sqlhist.bash ├── scripts ├── features.mk └── utils.mk ├── src ├── Makefile ├── meson.build ├── sqlhist-lex.c ├── sqlhist-parse.h ├── sqlhist.l ├── sqlhist.tab.c ├── sqlhist.tab.h ├── sqlhist.y ├── tracefs-dynevents.c ├── tracefs-eprobes.c ├── tracefs-events.c ├── tracefs-filter.c ├── tracefs-hist.c ├── tracefs-instance.c ├── tracefs-kprobes.c ├── tracefs-marker.c ├── tracefs-mmap.c ├── tracefs-perf.c ├── tracefs-record.c ├── tracefs-sqlhist.c ├── tracefs-stats.c ├── tracefs-tools.c ├── tracefs-uprobes.c ├── tracefs-utils.c ├── tracefs-vsock.c └── tracefs_sql.bash ├── test.c └── utest ├── Makefile ├── README ├── meson.build ├── trace-utest.c ├── trace-utest.h └── tracefs-utest.c /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | \#*\# 3 | .pc 4 | libtracefs.pc 5 | TAGS 6 | tags 7 | lib/ 8 | bin/ 9 | patches/ 10 | build_prefix 11 | build_uninstall 12 | tfs_version.h 13 | *.o 14 | .*.d 15 | sqlhist 16 | utest/trace-utest 17 | -------------------------------------------------------------------------------- /Documentation/.gitignore: -------------------------------------------------------------------------------- 1 | *.3 2 | sqlhist.1 3 | *.m 4 | *.xml 5 | *.html 6 | -------------------------------------------------------------------------------- /Documentation/asciidoc.conf: -------------------------------------------------------------------------------- 1 | ## linktep: macro 2 | # 3 | # Usage: linktep:command[manpage-section] 4 | # 5 | # Note, {0} is the manpage section, while {target} is the command. 6 | # 7 | # Show TEP link as: (
); if section is defined, else just show 8 | # the command. 9 | 10 | [macros] 11 | (?su)[\\]?(?Plinktep):(?P\S*?)\[(?P.*?)\]= 12 | 13 | [attributes] 14 | asterisk=* 15 | plus=+ 16 | caret=^ 17 | startsb=[ 18 | endsb=] 19 | tilde=~ 20 | 21 | ifdef::backend-docbook[] 22 | [linktep-inlinemacro] 23 | {0%{target}} 24 | {0#} 25 | {0#{target}{0}} 26 | {0#} 27 | endif::backend-docbook[] 28 | 29 | ifdef::backend-docbook[] 30 | ifndef::tep-asciidoc-no-roff[] 31 | # "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this. 32 | # v1.72 breaks with this because it replaces dots not in roff requests. 33 | [listingblock] 34 | {title} 35 | 36 | ifdef::doctype-manpage[] 37 | .ft C 38 | endif::doctype-manpage[] 39 | | 40 | ifdef::doctype-manpage[] 41 | .ft 42 | endif::doctype-manpage[] 43 | 44 | {title#} 45 | endif::tep-asciidoc-no-roff[] 46 | 47 | ifdef::tep-asciidoc-no-roff[] 48 | ifdef::doctype-manpage[] 49 | # The following two small workarounds insert a simple paragraph after screen 50 | [listingblock] 51 | {title} 52 | 53 | | 54 | 55 | {title#} 56 | 57 | [verseblock] 58 | {title} 59 | {title%} 60 | {title#} 61 | | 62 | 63 | {title#} 64 | {title%} 65 | endif::doctype-manpage[] 66 | endif::tep-asciidoc-no-roff[] 67 | endif::backend-docbook[] 68 | 69 | ifdef::doctype-manpage[] 70 | ifdef::backend-docbook[] 71 | [header] 72 | template::[header-declarations] 73 | 74 | 75 | {mantitle} 76 | {manvolnum} 77 | libtracefs 78 | {libtracefs_version} 79 | libtracefs Manual 80 | 81 | 82 | {manname1} 83 | {manname2} 84 | {manname3} 85 | {manname4} 86 | {manname5} 87 | {manname6} 88 | {manname7} 89 | {manname8} 90 | {manname9} 91 | {manname10} 92 | {manname11} 93 | {manname12} 94 | {manname13} 95 | {manname14} 96 | {manname15} 97 | {manname16} 98 | {manname17} 99 | {manname18} 100 | {manname19} 101 | {manname20} 102 | {manname21} 103 | {manname22} 104 | {manname23} 105 | {manname24} 106 | {manname25} 107 | {manname26} 108 | {manname27} 109 | {manname28} 110 | {manname29} 111 | {manname30} 112 | {manpurpose} 113 | 114 | endif::backend-docbook[] 115 | endif::doctype-manpage[] 116 | 117 | ifdef::backend-xhtml11[] 118 | [linktep-inlinemacro] 119 | {target}{0?({0})} 120 | endif::backend-xhtml11[] 121 | -------------------------------------------------------------------------------- /Documentation/install-docs.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: LGPL-2.1 3 | # 4 | # Copyright (c) 2023 Daniel Wagner, SUSE LLC 5 | 6 | for section in 1 3 5; do 7 | while IFS= read -r -d '' man; do 8 | [ ! -d "${DESTDIR}@MANDIR@/man${section}" ] && install -d "${DESTDIR}@MANDIR@/man${section}" 9 | 10 | echo Installing "${man}" to "${DESTDIR}@MANDIR@/man${section}" 11 | install -m 0644 "${man}" "${DESTDIR}@MANDIR@/man${section}/" 12 | done< <(find "@SRCDIR@" -name "*\.${section}" -type f -print0) 13 | done 14 | 15 | while IFS= read -r -d '' html; do 16 | [ ! -d "${DESTDIR}@HTMLDIR@" ] && install -d "${DESTDIR}@HTMLDIR@" 17 | 18 | echo Installing "${html}" to "${DESTDIR}@HTMLDIR@" 19 | install -m 0644 "${html}" "${DESTDIR}@HTMLDIR@" 20 | done< <(find "@SRCDIR@" -name "*\.html" -type f -print0) 21 | -------------------------------------------------------------------------------- /Documentation/libtracefs-cpu-buf.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_cpu_read_buf, tracefs_cpu_buffered_read_buf, tracefs_cpu_flush_buf 7 | - Reading trace_pipe_raw data returning a kbuffer 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | struct kbuffer pass:[*]*tracefs_cpu_read_buf*(struct tracefs_cpu pass:[*]_tcpu_, bool _nonblock_); 16 | struct kbuffer pass:[*]*tracefs_cpu_buffered_read_buf*(struct tracefs_cpu pass:[*]_tcpu_, bool _nonblock_); 17 | struct kbuffer pass:[*]*tracefs_cpu_flush_buf*(struct tracefs_cpu pass:[*]_tcpu_); 18 | -- 19 | 20 | DESCRIPTION 21 | ----------- 22 | This set of APIs can be used to read the raw data from the trace_pipe_raw 23 | files in the tracefs file system and return a kbuffer structure to read it with. 24 | 25 | The *tracefs_cpu_read_buf()* reads the trace_pipe_raw files associated to _tcpu_ 26 | and returns a kbuffer structure that can be used to iterate the events. 27 | If _nonblock_ is set, and there's no data available, it will return immediately. 28 | Otherwise depending on how _tcpu_ was opened, it will block. If _tcpu_ was 29 | opened with nonblock set, then this _nonblock_ will make no difference. 30 | 31 | The *tracefs_cpu_buffered_read_buf()* is basically the same as *tracefs_cpu_read_buf()* 32 | except that it uses a pipe through splice to buffer reads. This will batch 33 | reads keeping the reading from the ring buffer less intrusive to the system, 34 | as just reading all the time can cause quite a disturbance. Note, one 35 | difference between this and *tracefs_cpu_read()* is that it will read only in 36 | sub buffer pages. If the ring buffer has not filled a page, then it will not 37 | return anything, even with _nonblock_ set. Calls to *tracefs_cpu_flush_buf()* 38 | or *tracefs_cpu_flush()* should be done to read the rest of the file at the 39 | end of the trace. 40 | 41 | The *tracefs_cpu_flush_buf()* reads the trace_pipe_raw file associated by the 42 | _tcpu_ and puts it into _buffer_, which must be the size of the sub buffer 43 | which is retrieved. This should be called at the end of tracing 44 | to get the rest of the data. This call will convert the file descriptor of 45 | trace_pipe_raw into non-blocking mode. 46 | 47 | RETURN VALUE 48 | ------------ 49 | The functions *tracefs_cpu_read_buf()*, tracefs_cpu_buffered_read_buf()* and 50 | *tracefs_cpu_flush()* returns a kbuffer descriptor that can be iterated 51 | over to find the events. Note, this descriptor is part of the tracefs_cpu structure 52 | and should not be freed. It will be freed. It returns NULL on error or if nonblock 53 | is set and there are no events available. In the case of no events, errno will be 54 | set with EAGAIN. 55 | 56 | EXAMPLE 57 | ------- 58 | [source,c] 59 | -- 60 | #include 61 | #include 62 | #include 63 | 64 | static void read_page(struct tep_handle *tep, struct kbuffer *kbuf) 65 | { 66 | static struct trace_seq seq; 67 | struct tep_record record; 68 | 69 | if (seq.buffer) 70 | trace_seq_reset(&seq); 71 | else 72 | trace_seq_init(&seq); 73 | 74 | while ((record.data = kbuffer_read_event(kbuf, &record.ts))) { 75 | record.size = kbuffer_event_size(kbuf); 76 | kbuffer_next_event(kbuf, NULL); 77 | tep_print_event(tep, &seq, &record, 78 | "%s-%d %9d\t%s: %s\n", 79 | TEP_PRINT_COMM, 80 | TEP_PRINT_PID, 81 | TEP_PRINT_TIME, 82 | TEP_PRINT_NAME, 83 | TEP_PRINT_INFO); 84 | trace_seq_do_printf(&seq); 85 | trace_seq_reset(&seq); 86 | } 87 | } 88 | 89 | int main (int argc, char **argv) 90 | { 91 | struct tracefs_cpu *tcpu; 92 | struct tep_handle *tep; 93 | struct kbuffer *kbuf; 94 | int cpu; 95 | 96 | if (argc < 2 || !isdigit(argv[1][0])) { 97 | printf("usage: %s cpu\n\n", argv[0]); 98 | exit(-1); 99 | } 100 | 101 | cpu = atoi(argv[1]); 102 | 103 | tep = tracefs_local_events(NULL); 104 | if (!tep) { 105 | perror("Reading trace event formats"); 106 | exit(-1); 107 | } 108 | 109 | tcpu = tracefs_cpu_open(NULL, cpu, 0); 110 | if (!tcpu) { 111 | perror("Open CPU 0 file"); 112 | exit(-1); 113 | } 114 | 115 | while ((kbuf = tracefs_cpu_buffered_read_buf(tcpu, true))) { 116 | read_page(tep, kbuf); 117 | } 118 | 119 | kbuf = tracefs_cpu_flush_buf(tcpu); 120 | if (kbuf) 121 | read_page(tep, kbuf); 122 | 123 | tracefs_cpu_close(tcpu); 124 | tep_free(tep); 125 | 126 | return 0; 127 | } 128 | -- 129 | FILES 130 | ----- 131 | [verse] 132 | -- 133 | *tracefs.h* 134 | Header file to include in order to have access to the library APIs. 135 | *-ltracefs* 136 | Linker switch to add when building a program that uses the library. 137 | -- 138 | 139 | SEE ALSO 140 | -------- 141 | *tracefs_cpu_open*(3) 142 | *tracefs_cpu_close*(3) 143 | *tracefs_cpu_read*(3) 144 | *tracefs_cpu_buffered_read*(3) 145 | *tracefs_cpu_flush*(3) 146 | *libtracefs*(3), 147 | *libtraceevent*(3), 148 | *trace-cmd*(1) 149 | 150 | AUTHOR 151 | ------ 152 | [verse] 153 | -- 154 | *Steven Rostedt* 155 | -- 156 | REPORTING BUGS 157 | -------------- 158 | Report bugs to 159 | 160 | LICENSE 161 | ------- 162 | libtracefs is Free Software licensed under the GNU LGPL 2.1 163 | 164 | RESOURCES 165 | --------- 166 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 167 | 168 | COPYING 169 | ------- 170 | Copyright \(C) 2022 Google, Inc. Free use of this software is granted under 171 | the terms of the GNU Public License (GPL). 172 | -------------------------------------------------------------------------------- /Documentation/libtracefs-cpu-open.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_cpu_open, tracefs_cpu_close, tracefs_cpu_alloc_fd, tracefs_cpu_free_fd, tracefs_cpu_snapshot_open - Opening trace_pipe_raw data for reading 7 | 8 | SYNOPSIS 9 | -------- 10 | [verse] 11 | -- 12 | *#include * 13 | 14 | struct tracefs_cpu pass:[*]*tracefs_cpu_open*(struct tracefs_instance pass:[*]_instance_, 15 | int _cpu_, bool _nonblock_); 16 | void *tracefs_cpu_close*(struct tracefs_cpu pass:[*]_tcpu_); 17 | 18 | struct tracefs_cpu pass:[*]*tracefs_cpu_alloc_fd*(int _fd_, int _subbuf_size_, bool _nonblock_); 19 | void *tracefs_cpu_free_fd*(struct tracefs_cpu pass:[*]_tcpu_); 20 | 21 | struct tracefs_cpu pass:[*]*tracefs_cpu_snapshot_open*(struct tracefs_instance pass:[*]_instance_, 22 | int _cpu_, bool _nonblock_); 23 | -- 24 | 25 | DESCRIPTION 26 | ----------- 27 | This set of APIs can be used to open the raw data from the trace_pipe_raw 28 | files in the tracefs file system in oder to read them with the *tracefs_cpu_read*(3) 29 | functions. 30 | 31 | The *tracefs_cpu_open()* creates a descriptor that can read the tracefs 32 | trace_pipe_raw file for a given _cpu_ in a given _instance_. If _instance_ is 33 | NULL than the toplevel trace_pipe_raw file is used. 34 | 35 | The *tracefs_cpu_close()* closes all the file descriptors associated to the trace_pipe_raw 36 | opened by *tracefs_cpu_open()*. 37 | 38 | The *tracefs_cpu_alloc_fd()* will create a tracefs_cpu descriptor from an existing 39 | file descriptor _fd_. This is useful to use when connecting to a socket or pipe where 40 | the other end is feeding raw tracing data in the same format as the trace_pipe_raw 41 | file would (like in guest to host tracing). The caller is responsible for determining 42 | the _subbuf_size_ that will be used to break up the sub-buffers being read by the 43 | file descriptor. The _nonblock_ is treated the same as the same parameter in 44 | *tracefs_cpu_open()*. 45 | 46 | The *tracefs_cpu_free_fd()* is used to free the descriptor returned by *tracefs_cpu_alloc_fd()*. 47 | It does all the clean up that *tracefs_cpu_close()* performs, and that could also be 48 | used to free up the descriptor created by *tracefs_cpu_alloc_fd()* but will also close 49 | the file descriptor passed in. Note that *tracefs_cpu_free_fd()* should not be used 50 | on the descriptor returned by *tracefs_cpu_open()* as it will not close the file descriptor 51 | created by it. 52 | 53 | The *tracefs_cpu_snapshot_open()* is similar to *tracefs_cpu_open()* except that it 54 | opens the snapshot buffer (see *tracefs_snapshot_snap*(3)). The snapshot buffer 55 | does not have a writer to it, it is only created by a snapshot action that swaps 56 | the current ring buffer with the snapshot buffer. The _nonblock_, when false, acts a little 57 | differently here too. Reads are not affected by the "buffer_percent" file. If the 58 | snapshot buffer is empty, it will block until a new snapshot happens. 59 | 60 | RETURN VALUE 61 | ------------ 62 | The *tracefs_cpu_open()* and *tracefs_cpu_snapshot_open() both return a struct 63 | tracefs_cpu descriptor that can be used by the other functions or NULL on error. 64 | 65 | The *tracefs_cpu_alloc_fd()* returns a struct tracefs_cpu descriptor that can 66 | be used by the *tracefs_cpu_read*(3) related functions, where the descriptor 67 | will be reading the passed in _fd_ file descriptor. 68 | 69 | EXAMPLE 70 | ------- 71 | See *tracefs_cpu_read*(3) for an example. 72 | 73 | FILES 74 | ----- 75 | [verse] 76 | -- 77 | *tracefs.h* 78 | Header file to include in order to have access to the library APIs. 79 | *-ltracefs* 80 | Linker switch to add when building a program that uses the library. 81 | -- 82 | 83 | SEE ALSO 84 | -------- 85 | *libtracefs*(3), 86 | *libtraceevent*(3), 87 | *trace-cmd*(1) 88 | 89 | AUTHOR 90 | ------ 91 | [verse] 92 | -- 93 | *Steven Rostedt* 94 | -- 95 | REPORTING BUGS 96 | -------------- 97 | Report bugs to 98 | 99 | LICENSE 100 | ------- 101 | libtracefs is Free Software licensed under the GNU LGPL 2.1 102 | 103 | RESOURCES 104 | --------- 105 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 106 | 107 | COPYING 108 | ------- 109 | Copyright \(C) 2022 Google, Inc. Free use of this software is granted under 110 | the terms of the GNU Public License (GPL). 111 | -------------------------------------------------------------------------------- /Documentation/libtracefs-eprobes.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_eprobe_alloc - Allocate new event probe (eprobe) 7 | 8 | SYNOPSIS 9 | -------- 10 | [verse] 11 | -- 12 | *#include * 13 | 14 | struct tracefs_dynevent pass:[*] 15 | *tracefs_eprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, 16 | const char pass:[*]_target_system_, const char pass:[*]_target_event_, 17 | const char pass:[*]_fetchargs_); 18 | -- 19 | 20 | DESCRIPTION 21 | ----------- 22 | *tracefs_eprobe_alloc*() allocates a new eprobe context. The ebrobe is not configured in the system. 23 | The new eprobe will be in the _system_ group (or eprobes if _system_ is NULL) and have the name of 24 | _event_. The eprobe will be attached to _target_event_, located in _target_system_. The list of 25 | arguments, described in _fetchargs_, will be fetched from _target_event_. The returned pointer to 26 | the event probe must be freed with *tracefs_dynevent_free*(). 27 | 28 | 29 | RETURN VALUE 30 | ------------ 31 | The *tracefs_eprobe_alloc*() API returns a pointer to an allocated tracefs_dynevent structure, 32 | describing the event probe. This pointer must be freed by *tracefs_dynevent_free*(3). Note, this 33 | only allocates a descriptor representing the eprobe. It does not modify the running system. On error 34 | NULL is returned. 35 | 36 | EXAMPLE 37 | ------- 38 | [source,c] 39 | -- 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | 46 | static struct tep_event *open_event; 47 | static struct tep_format_field *file_field; 48 | 49 | static int callback(struct tep_event *event, struct tep_record *record, 50 | int cpu, void *data) 51 | { 52 | struct trace_seq seq; 53 | 54 | trace_seq_init(&seq); 55 | tep_print_event(event->tep, &seq, record, "%d-%s: ", TEP_PRINT_PID, TEP_PRINT_COMM); 56 | 57 | if (event->id == open_event->id) { 58 | trace_seq_puts(&seq, "open file='"); 59 | tep_print_field(&seq, record->data, file_field); 60 | trace_seq_puts(&seq, "'\n"); 61 | } 62 | 63 | trace_seq_terminate(&seq); 64 | trace_seq_do_printf(&seq); 65 | trace_seq_destroy(&seq); 66 | 67 | return 0; 68 | } 69 | 70 | static pid_t run_exec(char **argv, char **env) 71 | { 72 | pid_t pid; 73 | 74 | pid = fork(); 75 | if (pid) 76 | return pid; 77 | 78 | execve(argv[0], argv, env); 79 | perror("exec"); 80 | exit(-1); 81 | } 82 | 83 | const char *myprobe = "my_eprobes"; 84 | 85 | int main (int argc, char **argv, char **env) 86 | { 87 | struct tracefs_dynevent *eprobe; 88 | struct tracefs_instance *instance; 89 | struct tep_handle *tep; 90 | const char *sysnames[] = { myprobe, NULL }; 91 | pid_t pid; 92 | 93 | if (argc < 2) { 94 | printf("usage: %s command\n", argv[0]); 95 | exit(-1); 96 | } 97 | 98 | instance = tracefs_instance_create("exec_open"); 99 | if (!instance) { 100 | perror("creating instance"); 101 | exit(-1); 102 | } 103 | 104 | tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_EPROBE, true); 105 | 106 | eprobe = tracefs_eprobe_alloc(myprobe, "sopen", "syscalls", "sys_enter_openat2", 107 | "file=+0($filename):ustring"); 108 | if (!eprobe) { 109 | perror("allocating event probe"); 110 | exit(-1); 111 | } 112 | 113 | if (tracefs_dynevent_create(eprobe)) { 114 | perror("creating event probe"); 115 | exit(-1); 116 | } 117 | 118 | tep = tracefs_local_events_system(NULL, sysnames); 119 | if (!tep) { 120 | perror("reading events"); 121 | exit(-1); 122 | } 123 | 124 | open_event = tep_find_event_by_name(tep, myprobe, "sopen"); 125 | file_field = tep_find_field(open_event, "file"); 126 | 127 | tracefs_event_enable(instance, myprobe, "sopen"); 128 | pid = run_exec(&argv[1], env); 129 | 130 | /* Let the child start to run */ 131 | sched_yield(); 132 | 133 | do { 134 | tracefs_load_cmdlines(NULL, tep); 135 | tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, NULL); 136 | } while (waitpid(pid, NULL, WNOHANG) != pid); 137 | 138 | /* Will disable the events */ 139 | tracefs_dynevent_destroy(eprobe, true); 140 | tracefs_dynevent_free(eprobe); 141 | tracefs_instance_destroy(instance); 142 | tep_free(tep); 143 | 144 | return 0; 145 | } 146 | -- 147 | 148 | FILES 149 | ----- 150 | [verse] 151 | -- 152 | *tracefs.h* 153 | Header file to include in order to have access to the library APIs. 154 | *-ltracefs* 155 | Linker switch to add when building a program that uses the library. 156 | -- 157 | 158 | SEE ALSO 159 | -------- 160 | *libtracefs*(3), 161 | *libtraceevent*(3), 162 | *trace-cmd*(1) 163 | 164 | AUTHOR 165 | ------ 166 | [verse] 167 | -- 168 | *Steven Rostedt* 169 | *Tzvetomir Stoyanov* 170 | -- 171 | 172 | REPORTING BUGS 173 | -------------- 174 | Report bugs to 175 | 176 | LICENSE 177 | ------- 178 | libtracefs is Free Software licensed under the GNU LGPL 2.1 179 | 180 | RESOURCES 181 | --------- 182 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 183 | 184 | COPYING 185 | ------- 186 | Copyright \(C) 2021 VMware, Inc. Free use of this software is granted under 187 | the terms of the GNU Public License (GPL). 188 | -------------------------------------------------------------------------------- /Documentation/libtracefs-error.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_error_last, tracefs_error_all, tracefs_error_clear - 7 | functions to read and clear the tracefs error log. 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | char pass:[*]*tracefs_error_last*(struct tracefs_instance pass:[*]_instance_); 16 | char pass:[*]*tracefs_error_all*(struct tracefs_instance pass:[*]_instance_); 17 | int *tracefs_error_clear*(struct tracefs_instance pass:[*]_instance_); 18 | -- 19 | 20 | DESCRIPTION 21 | ----------- 22 | The *tracefs_error_last*() returns the last error message in the tracefs 23 | error log. Several actions that require proper syntax written into the 24 | tracefs file system may produce error messages in the error log. This 25 | function will show the most recent error in the error log. 26 | 27 | The *tracefs_error_all*() returns all messages saved in the error log. 28 | Note, this may not be all messages that were ever produced, as the kernel 29 | only keeps a limited amount of messages, and older ones may be discarded 30 | by the kernel. 31 | 32 | The *tracefs_error_clear*() will clear the error log. 33 | 34 | RETURN VALUE 35 | ------------ 36 | Both *tracefs_error_last*() and *tracefs_error_all*() will return an allocated 37 | string an error exists in the log, otherwise NULL is returned. If an error 38 | occurs, errno will be set, otherwise if there is no error messages to display 39 | then errno is not touched. 40 | 41 | *tracefs_error_clear*() returns 0 on success or -1 on error. 42 | 43 | EXAMPLE 44 | ------- 45 | [source,c] 46 | -- 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | 53 | int main (int argc, char **argv, char **env) 54 | { 55 | struct tracefs_dynevent *kevent; 56 | char *system = NULL; 57 | char *kprobe; 58 | char *format; 59 | char *addr; 60 | int arg = 1; 61 | int ret; 62 | 63 | if (argc < 4) { 64 | printf("usage: %s [system] kprobe addr fmt\n", argv[0]); 65 | exit(-1); 66 | } 67 | 68 | if (argc > 5) 69 | system = argv[arg++]; 70 | 71 | kprobe = argv[arg++]; 72 | addr = argv[arg++]; 73 | format = argv[arg++]; 74 | 75 | tracefs_error_clear(NULL); 76 | kevent = tracefs_dynevent_get(TRACEFS_DYNEVENT_KPROBE, system, kprobe); 77 | if (kevent) { 78 | tracefs_dynevent_destroy(kevent, true); 79 | tracefs_dynevent_free(kevent); 80 | } 81 | 82 | ret = tracefs_kprobe_raw(system, kprobe, addr, format); 83 | if (ret < 0) { 84 | char *err; 85 | 86 | perror("Failed creating kprobe"); 87 | errno = 0; 88 | err = tracefs_error_last(NULL); 89 | if (err) 90 | fprintf(stderr, "%s\n", err); 91 | else if (errno) 92 | perror("Failed reading error log"); 93 | free(err); 94 | } 95 | 96 | exit(ret); 97 | } 98 | -- 99 | FILES 100 | ----- 101 | [verse] 102 | -- 103 | *tracefs.h* 104 | Header file to include in order to have access to the library APIs. 105 | *-ltracefs* 106 | Linker switch to add when building a program that uses the library. 107 | -- 108 | 109 | SEE ALSO 110 | -------- 111 | *libtracefs*(3), 112 | *libtraceevent*(3), 113 | *trace-cmd*(1) 114 | 115 | AUTHOR 116 | ------ 117 | [verse] 118 | -- 119 | *Steven Rostedt* 120 | *Tzvetomir Stoyanov* 121 | -- 122 | REPORTING BUGS 123 | -------------- 124 | Report bugs to 125 | 126 | LICENSE 127 | ------- 128 | libtracefs is Free Software licensed under the GNU LGPL 2.1 129 | 130 | RESOURCES 131 | --------- 132 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 133 | 134 | COPYING 135 | ------- 136 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 137 | the terms of the GNU Public License (GPL). 138 | -------------------------------------------------------------------------------- /Documentation/libtracefs-events-tep.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_local_events, tracefs_local_events_system, tracefs_fill_local_events, 7 | tracefs_load_cmdlines, tracefs_load_headers - 8 | Initialize a tep handler with trace events from the local system. 9 | 10 | SYNOPSIS 11 | -------- 12 | [verse] 13 | -- 14 | *#include * 15 | 16 | struct tep_handle pass:[*]*tracefs_local_events*(const char pass:[*]_tracing_dir_); 17 | struct tep_handle pass:[*]*tracefs_local_events_system*(const char pass:[*]_tracing_dir_, const char pass:[*] const pass:[*]_sys_names_); 18 | int *tracefs_fill_local_events*(const char pass:[*]_tracing_dir_, struct tep_handle pass:[*]_tep_, int pass:[*]_parsing_failures_); 19 | int *tracefs_load_cmdlines*(const char pass:[*]_tracing_dir_, struct tep_handle pass:[*]_tep_); 20 | int *tracefs_load_headers*(const char pass:[*]_tracing_dir_, struct tep_handle pass:[*]_tep_); 21 | -- 22 | 23 | DESCRIPTION 24 | ----------- 25 | Functions for initializing a tep handler with trace events from the local system. 26 | 27 | The *tracefs_local_events()* function allocates a new _tep_ handler and 28 | initializes it with events from all trace systems, located in the given 29 | _tracing_dir_ directory. This could be NULL or the location of the tracefs 30 | mount point for the trace systems of the local machine, or it may be a path 31 | to a copy of the tracefs directory from another machine. 32 | 33 | The *tracefs_local_events_system()* function allocates a new _tep_ handler 34 | and initializes it with events from specified trace systems _sys_names_, 35 | located in the given _tracing_dir_ directory. This could be NULL or the 36 | location of the tracefs mount point for the trace systems of the local 37 | machine, or it may be a path to a copy of the tracefs directory from another 38 | machine. The _sys_names_ argument is an array of trace system names, that 39 | will be used for _tep_ handler initialization. The last element in that 40 | array must be a NULL pointer. 41 | 42 | The *tracefs_fill_local_events()* function initializes already allocated _tep_ 43 | handler with events from all trace systems, located in the given _tracing_dir_ 44 | directory. This could be NULL or the location of the tracefs mount point 45 | for the trace systems of the local machine, or it may be a path to a copy 46 | of the tracefs directory from another machine. The _tep_ argument must be 47 | a pointer to already allocated tep handler, that is going to be initialized. 48 | The _parsing_failures_ argument could be NULL or a pointer to an integer, 49 | where the number of failures while parsing the event files are returned. 50 | 51 | The above functions will also load the mappings between pids and the process 52 | command line names. In some cases the _tep_ handle is created with one 53 | of the above before tracing begins. As the mappings get updated during the 54 | trace, there may be a need to read the mappings again after the trace. 55 | The *tracefs_load_cmdlines()* does just that. The _tracing_dir_ is 56 | the directory of the mount point to load from, or NULL to use the 57 | mount point of the tracefs file system. 58 | 59 | The *tracefs_load_headers()* will reade the "header_page" of the events 60 | directory that will update the _tep_ handle with information on how to parse the 61 | tracing ring buffer sub-buffer. 62 | 63 | RETURN VALUE 64 | ------------ 65 | The *tracefs_local_events()* and *tracefs_local_events_system()* functions 66 | return pointer to allocated and initialized _tep_ handler, or NULL in 67 | case of an error. The returned _tep_ handler must be freed with *tep_free*(3). 68 | 69 | The *tracefs_fill_local_events()* function returns -1 in case of an error or 70 | 0 otherwise. 71 | 72 | The *tracefs_load_cmdlines()* function returns -1 in case of an error, or 73 | 0 otherwise. 74 | 75 | EXAMPLE 76 | ------- 77 | [source,c] 78 | -- 79 | #include 80 | 81 | struct tep_handle *tep; 82 | ... 83 | tep = tracefs_local_events(NULL); 84 | if (!tep) { 85 | /* Failed to initialise tep handler with local events from top instance */ 86 | ... 87 | } 88 | ... 89 | tep_free(tep); 90 | ... 91 | const char *systems[] = {"ftrace", "irq", NULL}; 92 | tep = tracefs_local_events_system(NULL, systems); 93 | if (!tep) { 94 | /* Failed to initialise tep handler with local events from 95 | * ftrace and irq systems in top instance. 96 | */ 97 | ... 98 | } 99 | ... 100 | tep_free(tep); 101 | ... 102 | int parsing_failures; 103 | tep = tep_alloc(); 104 | if (!tep) { 105 | /* Failed to allocate a tep handler */ 106 | ... 107 | } 108 | if (tracefs_fill_local_events(NULL, tep, &parsing_failures) < 0) { 109 | /* Failed to initialise tep handler with local events from top instance */ 110 | } 111 | tracefs_load_cmdlines(NULL, tep); 112 | ... 113 | tep_free(tep); 114 | -- 115 | FILES 116 | ----- 117 | [verse] 118 | -- 119 | *tracefs.h* 120 | Header file to include in order to have access to the library APIs. 121 | *-ltracefs* 122 | Linker switch to add when building a program that uses the library. 123 | -- 124 | 125 | SEE ALSO 126 | -------- 127 | *libtracefs*(3), 128 | *libtraceevent*(3), 129 | *trace-cmd*(1) 130 | 131 | AUTHOR 132 | ------ 133 | [verse] 134 | -- 135 | *Steven Rostedt* 136 | *Tzvetomir Stoyanov* 137 | -- 138 | REPORTING BUGS 139 | -------------- 140 | Report bugs to 141 | 142 | LICENSE 143 | ------- 144 | libtracefs is Free Software licensed under the GNU LGPL 2.1 145 | 146 | RESOURCES 147 | --------- 148 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 149 | 150 | COPYING 151 | ------- 152 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 153 | the terms of the GNU Public License (GPL). 154 | -------------------------------------------------------------------------------- /Documentation/libtracefs-files.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_get_tracing_file, tracefs_put_tracing_file, tracefs_tracing_dir, tracefs_debug_dir, tracefs_set_tracing_dir, 7 | tracefs_tracing_dir_is_mounted - Find and set locations of trace directory and files. 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | char pass:[*]*tracefs_get_tracing_file*(const char pass:[*]_name_); 16 | void *tracefs_put_tracing_file*(char pass:[*]_name_); 17 | const char pass:[*]*tracefs_tracing_dir*(void); 18 | const char pass:[*]*tracefs_debug_dir*(void); 19 | int *tracefs_set_tracing_dir*(char pass:[*]_tracing_dir_) 20 | int *tracefs_tracing_dir_is_mounted*(bool _mount_, const char pass:[**]_path_); 21 | -- 22 | 23 | DESCRIPTION 24 | ----------- 25 | This set of APIs can be used to find the full path of the trace file 26 | system mount point and trace files in it. 27 | 28 | The *tracefs_set_tracing_dir()* function sets a custom location of the 29 | system's tracing directory mount point. Usually, the library auto detects 30 | it using the information from the /proc/mounts file. Use this API only if the 31 | mount point is not standard and cannot be detected by the library. The _tracing_dir_ 32 | argument can be NULL, in that case the custom location is deleted and the library 33 | auto detection logic is used. 34 | 35 | The *tracefs_get_tracing_file()* function returns the full path of the 36 | file with given _name_ in the trace file system. The function works 37 | only with files in the tracefs main directory, it is not trace instance 38 | aware. It is recommended to use *tracefs_instance_get_file()* and 39 | *tracefs_instance_get_dir()* instead. The returned string must be freed 40 | with *tracefs_put_tracing_file()*. 41 | 42 | The *tracefs_put_tracing_file()* function frees trace file name, 43 | returned by *tracefs_get_tracing_file()*. 44 | 45 | The *tracefs_tracing_dir()* function returns the full path to the 46 | trace file system. In the first function call, the mount point of the 47 | tracing file system is located, cached and returned. It will mount it, 48 | if it is not mounted. On any subsequent call the cached path is returned. 49 | The return string must _not_ be freed. 50 | 51 | The *tracefs_debug_dir()* is similar to *tracefs_tracing_dir()* except 52 | that it will return where the debugfs file system is mounted. If it 53 | is not mounted it will try to mount it. The return string must _not_ 54 | be freed. 55 | 56 | *tracefs_tracing_dir_is_mounted()* returns 1 if the tracing directory is 57 | already mounted and 0 if it is not. If _mount_ is true, it will try to 58 | mount it if it is not, and returns 0 if it succesfully mounted it and -1 59 | if it did not. If _path_ is set, it will be assigned to the path where it 60 | mounted it. _path_ is internal and should not be freed. 61 | 62 | RETURN VALUE 63 | ------------ 64 | The *tracefs_set_tracing_dir()* function returns 0 on success, -1 otherwise. 65 | 66 | The *tracefs_get_tracing_file()* function returns a string or NULL in case 67 | of an error. The returned string must be freed with *tracefs_put_tracing_file()*. 68 | 69 | The *tracefs_tracing_dir()* function returns a constant string or NULL 70 | in case of an error. The returned string must _not_ be freed. 71 | 72 | The *tracefs_debug_dir()* function returns a constant string or NULL 73 | in case of an error. The returned string must _not_ be freed. 74 | 75 | The *tracefs_tracing_dir_is_mounted()* returns 1 if the tracing directory 76 | is already mounted, 0 if it is not, and -1 on error. 77 | 78 | EXAMPLE 79 | ------- 80 | [source,c] 81 | -- 82 | #include 83 | ... 84 | char *trace_on = tracefs_get_tracing_file("tracing_on"); 85 | if (trace_on) { 86 | ... 87 | tracefs_put_tracing_file(trace_on); 88 | } 89 | ... 90 | const char *trace_dir = tracefs_tracing_dir(); 91 | 92 | -- 93 | FILES 94 | ----- 95 | [verse] 96 | -- 97 | *tracefs.h* 98 | Header file to include in order to have access to the library APIs. 99 | *-ltracefs* 100 | Linker switch to add when building a program that uses the library. 101 | -- 102 | 103 | SEE ALSO 104 | -------- 105 | *libtracefs*(3), 106 | *libtraceevent*(3), 107 | *trace-cmd*(1) 108 | 109 | AUTHOR 110 | ------ 111 | [verse] 112 | -- 113 | *Steven Rostedt* 114 | *Tzvetomir Stoyanov* 115 | -- 116 | REPORTING BUGS 117 | -------------- 118 | Report bugs to 119 | 120 | LICENSE 121 | ------- 122 | libtracefs is Free Software licensed under the GNU LGPL 2.1 123 | 124 | RESOURCES 125 | --------- 126 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 127 | 128 | COPYING 129 | ------- 130 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 131 | the terms of the GNU Public License (GPL). 132 | -------------------------------------------------------------------------------- /Documentation/libtracefs-filter-pid.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_filter_pid_function, tracefs_filter_pid_events, tracefs_filter_pid_function_clear, tracefs_filter_pid_events_clear - 7 | Add and remove PID filtering for functions and events 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | int *tracefs_filter_pid_function*(struct tracefs_instance pass:[*]_instance,_ int _pid_, 16 | bool _reset_, bool _notrace_); 17 | int *tracefs_filter_pid_function_clear*(struct tracefs_instance pass:[*]_instance_, bool _notrace_); 18 | int *tracefs_filter_pid_events*(struct tracefs_instance pass:[*]_instance_, int _pid_, 19 | bool _reset_, bool _notrace_); 20 | int *tracefs_filter_pid_events_clear*(struct tracefs_instance pass:[*]_instance_, bool _notrace_); 21 | -- 22 | 23 | DESCRIPTION 24 | ----------- 25 | Both events and functions can be filtered by PID, but they are done separately. 26 | PID filtering for functions affect the function and function_graph tracer, where 27 | as PID filtering for events affect all events such as _sched_switch_ and _sched_waking_. 28 | If the *TRACEFS_OPTION_FUNCTION_FORK* is enabled (see *tracefs_option_enable*(3)), 29 | any PID that is set as part of the function PID filtering will automatically 30 | have its children added when they are spawned, as well as the PID removed when 31 | they exit. If the *TRACEFS_OPTION_EVENT_FORK* is set, the same is true for 32 | event PID filtering. This also includes the _notrace_ option where the child 33 | threads and processes of PIDs that are labled as notrace will also not be 34 | traced. 35 | 36 | The *tracefs_filter_pid_function()* affects function PID filtering and *tracefs_filter_pid_events()* 37 | affects the PID event filtering. For both functions, they add a _pid_ to be filtered in the given _instance_. 38 | If _reset_ is true, then any PIDs already being filtered will be removed, otherwise 39 | the _pid_ is simply added to the filtering. If _notrace_ is true, then the PID 40 | is added to the list of PIDs that are not to be traced. Note, that _reset_ only affects 41 | the list associated with _notrace_. That is, if both _reset_ and _notrace_ are true, 42 | then it will not affect PIDs that are to be traced. Same is if _reset_ is true and _notrace_ 43 | is false, it will not affect PIDs that are not to be traced. 44 | 45 | The *tracefs_filter_pid_function_clear()* affects function PID filtering and 46 | *tracefs_filter_pid_events_clear()* affects the PID event filtering. For both 47 | functions it will clear all the PIDs that are being filtered for the given 48 | filter. If _notrace_ is true it clears all the PIDs that are not to be traced 49 | otherwise if it is false, it clears all the PIDs that are to be traced. 50 | 51 | RETURN VALUE 52 | ------------ 53 | All the functions return 0 on success and -1 on error. 54 | 55 | EXAMPLE 56 | ------- 57 | [source,c] 58 | -- 59 | #include 60 | #include 61 | #include 62 | #include 63 | 64 | static void usage(char **argv) 65 | { 66 | fprintf(stderr, "usage: %s [-e|-f][-c|-n] pid [pid ...]\n", argv[0]); 67 | fprintf(stderr, " -e enable event filter\n"); 68 | fprintf(stderr, " -f enable function filter\n"); 69 | fprintf(stderr, " (default is both, function and event)\n"); 70 | fprintf(stderr, " -c clear the filter\n"); 71 | fprintf(stderr, " -n notrace filter\n"); 72 | exit(-1); 73 | } 74 | 75 | int main (int argc, char **argv) 76 | { 77 | bool events = false; 78 | bool funcs = false; 79 | bool neg = false; 80 | bool clear = false; 81 | bool reset = true; 82 | int i; 83 | 84 | for (i = 1; i < argc && argv[i][0] == '-'; i++) { 85 | char *arg = argv[i]; 86 | int c; 87 | for (c = 1; arg[c]; c++) { 88 | switch (arg[c]) { 89 | case 'e': events = true; break; 90 | case 'f': funcs = true; break; 91 | case 'n': neg = true; break; 92 | case 'c': clear = true; break; 93 | default: 94 | usage(argv); 95 | } 96 | } 97 | if (c == 1) 98 | usage(argv); 99 | } 100 | 101 | if (i == argc && !clear) 102 | usage(argv); 103 | 104 | if (!events && !funcs) { 105 | events = true; 106 | funcs = true; 107 | } 108 | 109 | if (clear) { 110 | if (events) 111 | tracefs_filter_pid_events_clear(NULL, neg); 112 | if (funcs) 113 | tracefs_filter_pid_function_clear(NULL, neg); 114 | exit(0); 115 | } 116 | 117 | for (; i < argc; i++) { 118 | int pid = atoi(argv[i]); 119 | 120 | if (events) 121 | tracefs_filter_pid_events(NULL, pid, reset, neg); 122 | if (funcs) 123 | tracefs_filter_pid_function(NULL, pid, reset, neg); 124 | 125 | reset = false; 126 | } 127 | 128 | exit(0); 129 | } 130 | 131 | -- 132 | 133 | FILES 134 | ----- 135 | [verse] 136 | -- 137 | *tracefs.h* 138 | Header file to include in order to have access to the library APIs. 139 | *-ltracefs* 140 | Linker switch to add when building a program that uses the library. 141 | -- 142 | 143 | SEE ALSO 144 | -------- 145 | *libtracefs*(3), 146 | *libtraceevent*(3), 147 | *trace-cmd*(1), 148 | *tracefs_hist_alloc*(3), 149 | *tracefs_hist_alloc_2d*(3), 150 | *tracefs_hist_alloc_nd*(3), 151 | *tracefs_hist_free*(3), 152 | *tracefs_hist_add_key*(3), 153 | *tracefs_hist_add_value*(3), 154 | *tracefs_hist_add_name*(3), 155 | *tracefs_hist_start*(3), 156 | *tracefs_hist_destory*(3), 157 | *tracefs_hist_add_sort_key*(3), 158 | *tracefs_hist_sort_key_direction*(3) 159 | 160 | AUTHOR 161 | ------ 162 | [verse] 163 | -- 164 | *Steven Rostedt* 165 | -- 166 | REPORTING BUGS 167 | -------------- 168 | Report bugs to 169 | 170 | LICENSE 171 | ------- 172 | libtracefs is Free Software licensed under the GNU LGPL 2.1 173 | 174 | RESOURCES 175 | --------- 176 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 177 | 178 | COPYING 179 | ------- 180 | Copyright \(C) 2023 Google, LLC. Free use of this software is granted under 181 | the terms of the GNU Public License (GPL). 182 | -------------------------------------------------------------------------------- /Documentation/libtracefs-guest.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_find_cid_pid, tracefs_instance_find_cid_pid, tracefs_time_conversion - 7 | helper functions to handle tracing guests 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | char pass:[*]*tracefs_find_cid_pid*(int _cid_); 16 | char pass:[*]*tracefs_instance_find_cid_pid*(struct tracefs_instance pass:[*]_instance_, int _cid_); 17 | int *tracefs_time_conversion*(int _cpu_, int pass:[*]_shift_, int pass:[*]_multi_, long long pass:[*]offset); 18 | -- 19 | 20 | DESCRIPTION 21 | ----------- 22 | The *tracefs_find_cid_pid*() will use tracing to follow the wakeups of connecting to 23 | the given _cid_ in order to find the pid of the guest thread that belongs to the vsocket cid. 24 | It will then read the proc file system to find the thread leader, and it will return 25 | the pid of the thread leader. 26 | 27 | The *tracefs_instance_find_cid_pid*() is the same as *tracefs_find_cid_pid*() but defines 28 | the instance to use to perform the tracing in. If NULL it will use the top level 29 | buffer to perform the tracing. 30 | 31 | The *tracefs_time_conversion*() will return the values used by the kernel to convert 32 | the raw time stamp counter into nanoseconds for the given _cpu_. Pointers for _shift_, _multi_ 33 | and _offset_ can be NULL to be ignored, otherwise they are set with the shift, multiplier 34 | and offset repectively. 35 | 36 | RETURN VALUE 37 | ------------ 38 | Both *tracefs_find_cid_pid*() and *tracefs_instance_find_cid_pid*() will return the 39 | pid of the guest main thread that belongs to the _cid_, or -1 on error (or not found). 40 | 41 | EXAMPLE 42 | ------- 43 | [source,c] 44 | -- 45 | #include 46 | #include 47 | #include 48 | 49 | #define MAX_CID 256 50 | 51 | static void find_cid(struct tracefs_instance *instance, int cid) 52 | { 53 | int pid; 54 | 55 | pid = tracefs_instance_find_cid_pid(instance, cid); 56 | if (pid >= 0) 57 | printf("%d\t%d\n", cid, pid); 58 | } 59 | 60 | static int find_cids(void) 61 | { 62 | struct tracefs_instance *instance; 63 | char *name; 64 | int cid; 65 | int ret; 66 | 67 | ret = asprintf(&name, "vsock_find-%d\n", getpid()); 68 | if (ret < 0) 69 | return ret; 70 | 71 | instance = tracefs_instance_create(name); 72 | free(name); 73 | if (!instance) 74 | return -1; 75 | 76 | for (cid = 0; cid < MAX_CID; cid++) 77 | find_cid(instance, cid); 78 | 79 | tracefs_event_disable(instance, NULL, NULL); 80 | tracefs_instance_destroy(instance); 81 | tracefs_instance_free(instance); 82 | return 0; 83 | } 84 | 85 | struct time_info { 86 | int shift; 87 | int multi; 88 | }; 89 | 90 | static void show_time_conversion(void) 91 | { 92 | struct time_info *tinfo; 93 | int cpus; 94 | int cpu; 95 | int ret; 96 | 97 | cpus = sysconf(_SC_NPROCESSORS_CONF); 98 | tinfo = calloc(cpus, sizeof(*tinfo)); 99 | if (!tinfo) 100 | exit(-1); 101 | 102 | for (cpu = 0; cpu < cpus; cpu++) { 103 | ret = tracefs_time_conversion(cpu, 104 | &tinfo[cpu].shift, 105 | &tinfo[cpu].multi, 106 | NULL); 107 | if (ret) 108 | break; 109 | } 110 | if (cpu != cpus) { 111 | if (!cpu) { 112 | perror("tracefs_time_conversion"); 113 | exit(-1); 114 | } 115 | printf("Only read %d of %d CPUs", cpu, cpus); 116 | cpus = cpu + 1; 117 | } 118 | 119 | /* Check if all the shift and mult values are the same */ 120 | for (cpu = 1; cpu < cpus; cpu++) { 121 | if (tinfo[cpu - 1].shift != tinfo[cpu].shift) 122 | break; 123 | if (tinfo[cpu - 1].multi != tinfo[cpu].multi) 124 | break; 125 | } 126 | 127 | if (cpu == cpus) { 128 | printf("All cpus have:\n"); 129 | printf(" shift: %d\n", tinfo[0].shift); 130 | printf(" multi: %d\n", tinfo[0].multi); 131 | printf("\n"); 132 | return; 133 | } 134 | 135 | for (cpu = 0; cpu < cpus; cpu++) { 136 | printf("CPU: %d\n", cpu); 137 | printf(" shift: %d\n", tinfo[cpu].shift); 138 | printf(" multi: %d\n", tinfo[cpu].multi); 139 | printf("\n"); 140 | } 141 | } 142 | 143 | int main(int argc, char *argv[]) 144 | { 145 | show_time_conversion(); 146 | find_cids(); 147 | exit(0); 148 | } 149 | -- 150 | FILES 151 | ----- 152 | [verse] 153 | -- 154 | *tracefs.h* 155 | Header file to include in order to have access to the library APIs. 156 | *-ltracefs* 157 | Linker switch to add when building a program that uses the library. 158 | -- 159 | 160 | SEE ALSO 161 | -------- 162 | *libtracefs*(3), 163 | *libtraceevent*(3), 164 | *trace-cmd*(1) 165 | 166 | AUTHOR 167 | ------ 168 | [verse] 169 | -- 170 | *Steven Rostedt* 171 | *Tzvetomir Stoyanov* 172 | -- 173 | REPORTING BUGS 174 | -------------- 175 | Report bugs to 176 | 177 | LICENSE 178 | ------- 179 | libtracefs is Free Software licensed under the GNU LGPL 2.1 180 | 181 | RESOURCES 182 | --------- 183 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 184 | 185 | COPYING 186 | ------- 187 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 188 | the terms of the GNU Public License (GPL). 189 | -------------------------------------------------------------------------------- /Documentation/libtracefs-hist-cont.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_hist_start, tracefs_hist_destroy, tracefs_hist_pause, 7 | tracefs_hist_continue, tracefs_hist_reset - Pause, continue, or clear an existing histogram 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | int *tracefs_hist_start*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_); 16 | int *tracefs_hist_destroy*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_); 17 | int *tracefs_hist_pause*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_); 18 | int *tracefs_hist_continue*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_); 19 | int *tracefs_hist_reset*(struct tracefs_instance pass:[*]_instance_, struct tracefs_hist pass:[*]_hist_); 20 | 21 | -- 22 | 23 | DESCRIPTION 24 | ----------- 25 | 26 | *tracefs_hist_start()* is called to actually start the histogram _hist_. 27 | The _instance_ is the instance to start the histogram in, NULL if it 28 | should start at the top level. 29 | 30 | *tracefs_hist_pause()* is called to pause the histogram _hist_. 31 | The _instance_ is the instance to pause the histogram in, NULL if it 32 | is in the top level. 33 | 34 | *tracefs_hist_continue()* is called to continue a paused histogram _hist_. 35 | The _instance_ is the instance to continue the histogram, NULL if it 36 | is in the top level. 37 | 38 | *tracefs_hist_reset()* is called to clear / reset the histogram _hist_. 39 | The _instance_ is the instance to clear the histogram, NULL if it 40 | is in the top level. 41 | 42 | *tracefs_hist_destroy()* is called to delete the histogram where it will no longer 43 | exist. The _instance_ is the instance to delete the histogram from, NULL if it 44 | is in the top level. 45 | 46 | RETURN VALUE 47 | ------------ 48 | All the return zero on success or -1 on error. 49 | 50 | EXAMPLE 51 | ------- 52 | [source,c] 53 | -- 54 | #include 55 | #include 56 | 57 | enum commands { 58 | START, 59 | PAUSE, 60 | CONT, 61 | RESET, 62 | DELETE, 63 | SHOW, 64 | }; 65 | 66 | int main (int argc, char **argv, char **env) 67 | { 68 | struct tracefs_instance *instance; 69 | struct tracefs_hist *hist; 70 | struct tep_handle *tep; 71 | enum commands cmd; 72 | char *cmd_str; 73 | int ret; 74 | 75 | if (argc < 2) { 76 | fprintf(stderr, "usage: %s command\n", argv[0]); 77 | exit(-1); 78 | } 79 | 80 | cmd_str = argv[1]; 81 | 82 | if (!strcmp(cmd_str, "start")) 83 | cmd = START; 84 | else if (!strcmp(cmd_str, "pause")) 85 | cmd = PAUSE; 86 | else if (!strcmp(cmd_str, "cont")) 87 | cmd = CONT; 88 | else if (!strcmp(cmd_str, "reset")) 89 | cmd = RESET; 90 | else if (!strcmp(cmd_str, "delete")) 91 | cmd = DELETE; 92 | else if (!strcmp(cmd_str, "show")) 93 | cmd = SHOW; 94 | else { 95 | fprintf(stderr, "Unknown command %s\n", cmd_str); 96 | exit(-1); 97 | } 98 | 99 | tep = tracefs_local_events(NULL); 100 | if (!tep) { 101 | perror("Reading tracefs"); 102 | exit(-1); 103 | } 104 | 105 | instance = tracefs_instance_create("hist_test"); 106 | if (!instance) { 107 | fprintf(stderr, "Failed instance create\n"); 108 | exit(-1); 109 | } 110 | 111 | hist = tracefs_hist_alloc_2d(tep, "kmem", "kmalloc", 112 | "call_site",TRACEFS_HIST_KEY_SYM, 113 | "bytes_req", 0); 114 | if (!hist) { 115 | fprintf(stderr, "Failed hist create\n"); 116 | exit(-1); 117 | } 118 | 119 | ret = tracefs_hist_add_value(hist, "bytes_alloc"); 120 | ret |= tracefs_hist_add_sort_key(hist, "bytes_req"); 121 | ret |= tracefs_hist_add_sort_key(hist, "bytes_alloc"); 122 | 123 | ret |= tracefs_hist_sort_key_direction(hist, "bytes_alloc", 124 | TRACEFS_HIST_SORT_DESCENDING); 125 | if (ret) { 126 | fprintf(stderr, "Failed modifying histogram\n"); 127 | exit(-1); 128 | } 129 | 130 | tracefs_error_clear(instance); 131 | 132 | switch (cmd) { 133 | case START: 134 | ret = tracefs_hist_start(instance, hist); 135 | if (ret) { 136 | char *err = tracefs_error_last(instance); 137 | if (err) 138 | fprintf(stderr, "\n%s\n", err); 139 | } 140 | break; 141 | case PAUSE: 142 | ret = tracefs_hist_pause(instance, hist); 143 | break; 144 | case CONT: 145 | ret = tracefs_hist_continue(instance, hist); 146 | break; 147 | case RESET: 148 | ret = tracefs_hist_reset(instance, hist); 149 | break; 150 | case DELETE: 151 | ret = tracefs_hist_destroy(instance, hist); 152 | break; 153 | case SHOW: { 154 | char *content; 155 | content = tracefs_event_file_read(instance, "kmem", "kmalloc", 156 | "hist", NULL); 157 | ret = content ? 0 : -1; 158 | if (content) { 159 | printf("%s\n", content); 160 | free(content); 161 | } 162 | break; 163 | } 164 | } 165 | if (ret) 166 | fprintf(stderr, "Failed: command\n"); 167 | exit(ret); 168 | } 169 | 170 | -- 171 | 172 | FILES 173 | ----- 174 | [verse] 175 | -- 176 | *tracefs.h* 177 | Header file to include in order to have access to the library APIs. 178 | *-ltracefs* 179 | Linker switch to add when building a program that uses the library. 180 | -- 181 | 182 | SEE ALSO 183 | -------- 184 | *libtracefs*(3), 185 | *libtraceevent*(3), 186 | *trace-cmd*(1), 187 | *tracefs_hist_alloc*(3), 188 | *tracefs_hist_alloc_2d*(3), 189 | *tracefs_hist_alloc_nd*(3), 190 | *tracefs_hist_free*(3), 191 | *tracefs_hist_add_key*(3), 192 | *tracefs_hist_add_value*(3), 193 | *tracefs_hist_add_name*(3), 194 | *tracefs_hist_start*(3), 195 | *tracefs_hist_destory*(3), 196 | *tracefs_hist_add_sort_key*(3), 197 | *tracefs_hist_sort_key_direction*(3) 198 | 199 | AUTHOR 200 | ------ 201 | [verse] 202 | -- 203 | *Steven Rostedt* 204 | *Tzvetomir Stoyanov* 205 | *sameeruddin shaik* 206 | -- 207 | REPORTING BUGS 208 | -------------- 209 | Report bugs to 210 | 211 | LICENSE 212 | ------- 213 | libtracefs is Free Software licensed under the GNU LGPL 2.1 214 | 215 | RESOURCES 216 | --------- 217 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 218 | 219 | COPYING 220 | ------- 221 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 222 | the terms of the GNU Public License (GPL). 223 | -------------------------------------------------------------------------------- /Documentation/libtracefs-instances-affinity.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_instance_set_affinity, tracefs_instance_set_affinity_set, tracefs_instance_set_affinity_raw, 7 | tracefs_instance_get_affinity, tracefs_instance_get_affinity_set, tracefs_instance_get_affinity_raw 8 | - Sets or retrieves the affinity for an instance or top level for what CPUs enable tracing. 9 | 10 | SYNOPSIS 11 | -------- 12 | [verse] 13 | -- 14 | *#include * 15 | 16 | int *tracefs_instance_set_affinity*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_cpu_str_); 17 | int *tracefs_instance_set_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_); 18 | int *tracefs_instance_set_affinity_raw*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_mask_); 19 | 20 | char pass:[*]*tracefs_instance_get_affinity*(struct tracefs_instance pass:[*]_instance_); 21 | int *tracefs_instance_get_affinity_set*(struct tracefs_instance pass:[*]_instance_, cpu_set_t pass:[*]_set_, size_t _set_size_); 22 | char pass:[*]*tracefs_instance_get_affinity_raw*(struct tracefs_instance pass:[*]_instance_); 23 | -- 24 | 25 | DESCRIPTION 26 | ----------- 27 | These functions set or retrieve the CPU affinity that limits what CPUs will have tracing enabled 28 | for a given instance defined by the _instance_ parameter. If _instance_ is NULL, then 29 | the top level instance is affected. 30 | 31 | The *tracefs_instance_set_affinity()* function takes a string _cpu_str_ that is a 32 | list of CPUs to set the affinity for. If _cpu_str_ is NULL, then all the CPUs in 33 | the system will be set. The format of _cpu_str_ is a comma delimited string of 34 | decimal numbers with no spaces. A range may be specified by a hyphen. 35 | 36 | For example: "1,4,6-8" 37 | 38 | The numbers do not need to be in order except for ranges, where the second number 39 | must be equal to or greater than the first. 40 | 41 | The *tracefs_instance_set_affinity_set()* function takes a CPU set defined by 42 | *CPU_SET*(3). The size of the set defined by _set_size_ is the size in bytes of 43 | _set_. If _set_ is NULL then all the CPUs on the system will be set, and _set_size_ 44 | is ignored. 45 | 46 | The *tracefs_instance_set_affinity_raw()* function takes a string that holds 47 | a hexidecimal bitmask, where each 32 bits is separated by a comma. For a 48 | machine with more that 32 CPUs, to set CPUS 1-10 and CPU 40: 49 | 50 | "100,000007fe" 51 | 52 | Where the above is a hex representation of bits 1-10 and bit 40 being set. 53 | 54 | The *tracefs_instance_get_affinity()* will retrieve the affinity in a human readable 55 | form. 56 | 57 | For example: "1,4,6-8" 58 | 59 | The string returned must be freed with *free*(3). 60 | 61 | The *tracefs_instance_get_affinity_set()* will set all the bits in the passed in 62 | cpu set (from *CPU_SET*(3)). Note it will not clear any bits that are already set 63 | in the set but the CPUs are not. If only the bits for the CPUs that are enabled 64 | should be set, a CPU_ZERO_S() should be performed on the set before calling this 65 | function. 66 | 67 | The *tracefs_instance_get_affinity_raw()* will simply read the instance tracing_cpumask 68 | and return that string. The returned string must be freed with *free*(3). 69 | 70 | RETURN VALUE 71 | ------------ 72 | All the set functions return 0 on success and -1 on error. 73 | 74 | The functions *tracefs_instance_get_affinity()* and *tracefs_instance_get_affinity_raw()* 75 | returns an allocated string that must be freed with *free*(3), or NULL on error. 76 | 77 | The function *tracefs_instance_get_affinity_set()* returns the number of CPUs that 78 | were found set, or -1 on error. 79 | 80 | 81 | ERRORS 82 | ------ 83 | The following errors are for all the above calls: 84 | 85 | *EFBIG* if a CPU is set that is greater than what is in the system. 86 | 87 | *EINVAL* One of the parameters was invalid. 88 | 89 | The following errors are for *tracefs_instance_set_affinity*() and *tracefs_instance_set_affinity_set*(): 90 | 91 | *ENOMEM* Memory allocation error. 92 | 93 | *ENODEV* dynamic events of requested type are not configured for the running kernel. 94 | 95 | The following errors are just for *tracefs_instance_set_affinity*() 96 | 97 | *EACCES* The _cpu_str_ was modified by another thread when processing it. 98 | 99 | EXAMPLE 100 | ------- 101 | [source,c] 102 | -- 103 | #include 104 | #include 105 | #include 106 | #include 107 | 108 | int main (int argc, char **argv) 109 | { 110 | struct trace_seq seq; 111 | cpu_set_t *set; 112 | size_t set_size; 113 | char *c; 114 | int cpu1; 115 | int cpu2; 116 | int i; 117 | 118 | c = tracefs_instance_get_affinity(NULL); 119 | printf("The affinity was %s\n", c); 120 | free(c); 121 | 122 | if (argc < 2) { 123 | tracefs_instance_set_affinity(NULL, NULL); 124 | exit(0); 125 | } 126 | /* Show example using a set */ 127 | if (argc == 2 && !strchr(argv[1],',')) { 128 | cpu1 = atoi(argv[1]); 129 | c = strchr(argv[1], '-'); 130 | if (c++) 131 | cpu2 = atoi(c); 132 | else 133 | cpu2 = cpu1; 134 | if (cpu2 < cpu1) { 135 | fprintf(stderr, "Invalid CPU range\n"); 136 | exit(-1); 137 | } 138 | set = CPU_ALLOC(cpu2 + 1); 139 | set_size = CPU_ALLOC_SIZE(cpu2 + 1); 140 | CPU_ZERO_S(set_size, set); 141 | for ( ; cpu1 <= cpu2; cpu1++) 142 | CPU_SET(cpu1, set); 143 | tracefs_instance_set_affinity_set(NULL, set, set_size); 144 | CPU_FREE(set); 145 | exit(0); 146 | } 147 | 148 | trace_seq_init(&seq); 149 | for (i = 1; i < argc; i++) { 150 | if (i > 1) 151 | trace_seq_putc(&seq, ','); 152 | trace_seq_puts(&seq, argv[i]); 153 | } 154 | trace_seq_terminate(&seq); 155 | tracefs_instance_set_affinity(NULL, seq.buffer); 156 | trace_seq_destroy(&seq); 157 | exit(0); 158 | 159 | return 0; 160 | } 161 | -- 162 | FILES 163 | ----- 164 | [verse] 165 | -- 166 | *tracefs.h* 167 | Header file to include in order to have access to the library APIs. 168 | *-ltracefs* 169 | Linker switch to add when building a program that uses the library. 170 | -- 171 | 172 | SEE ALSO 173 | -------- 174 | *libtracefs*(3), 175 | *libtraceevent*(3), 176 | *trace-cmd*(1) 177 | 178 | AUTHOR 179 | ------ 180 | [verse] 181 | -- 182 | *Steven Rostedt* 183 | *Tzvetomir Stoyanov* 184 | -- 185 | REPORTING BUGS 186 | -------------- 187 | Report bugs to 188 | 189 | LICENSE 190 | ------- 191 | libtracefs is Free Software licensed under the GNU LGPL 2.1 192 | 193 | RESOURCES 194 | --------- 195 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 196 | 197 | COPYING 198 | ------- 199 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 200 | the terms of the GNU Public License (GPL). 201 | -------------------------------------------------------------------------------- /Documentation/libtracefs-instances-files.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_file_exists, tracefs_dir_exists, 7 | tracefs_instance_get_file, tracefs_instance_get_dir - Work with files directories in tracing instances. 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | bool *tracefs_file_exists*(struct tracefs_instance pass:[*]_instance_, char pass:[*]_name_); 16 | bool *tracefs_dir_exists*(struct tracefs_instance pass:[*]_instance_, char pass:[*]_name_); 17 | char pass:[*]*tracefs_instance_get_file*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_file_); 18 | char pass:[*]*tracefs_instance_get_dir*(struct tracefs_instance pass:[*]_instance_); 19 | 20 | -- 21 | 22 | DESCRIPTION 23 | ----------- 24 | This set of APIs can be used to work with trace files in all trace instances. 25 | Each of these APIs take an _instance_ argument, that can be NULL to act 26 | on the top level instance. Otherwise, it acts on an instance created with 27 | *tracefs_insance_create*(3) 28 | 29 | The *tracefs_file_exists()* function checks if a file with _name_ exists in _instance_. 30 | 31 | The *tracefs_dir_exists()* function checks if a directory with _name_ exists in _instance_. 32 | 33 | The *tracefs_instance_get_file()* function returns the full path of the file 34 | with given _name_ in _instance_. Note, it does not check if the file exists in 35 | the instance. 36 | 37 | The *tracefs_instance_get_dir()* function returns the full path of the directory 38 | with given _name_ in _instance_. Note, it does not check if the directory exists 39 | in the instance. 40 | 41 | RETURN VALUE 42 | ------------ 43 | The *tracefs_file_exists()* and *tracefs_dir_exists()* functions return true if the 44 | file / directory exist in the given instance or false if it does not exist. 45 | 46 | The *tracefs_instance_get_file()* and *tracefs_instance_get_dir()* functions return 47 | a string or NULL in case of an error. The returned string must be freed with 48 | *tracefs_put_tracing_file()*. 49 | 50 | EXAMPLE 51 | ------- 52 | [source,c] 53 | -- 54 | #include 55 | 56 | struct tracefs_instance *inst = tracefs_instance_create("foo"); 57 | if (!inst) { 58 | /* Error creating a new trace instance */ 59 | ... 60 | } 61 | 62 | if (tracefs_file_exists(inst,"trace_clock")) { 63 | /* The instance foo supports trace clock */ 64 | char *path, *clock; 65 | int size; 66 | 67 | path = = tracefs_instance_get_file(inst, "trace_clock") 68 | if (!path) { 69 | /* Error getting the path to trace_clock file in instance foo */ 70 | ... 71 | } 72 | ... 73 | tracefs_put_tracing_file(path); 74 | 75 | clock = tracefs_instance_file_read(inst, "trace_clock", &size); 76 | if (!clock) { 77 | /* Failed to read trace_clock file in instance foo */ 78 | ... 79 | } 80 | ... 81 | free(clock); 82 | 83 | if (tracefs_instance_file_write(inst, "trace_clock", "global") != strlen("global")) { 84 | /* Failed to set gloabl trace clock in instance foo */ 85 | ... 86 | } 87 | } else { 88 | /* The instance foo does not support trace clock */ 89 | } 90 | 91 | if (tracefs_dir_exists(inst,"options")) { 92 | /* The instance foo supports trace options */ 93 | char *path = tracefs_instance_get_file(inst, "options"); 94 | if (!path) { 95 | /* Error getting the path to options directory in instance foo */ 96 | ... 97 | } 98 | 99 | tracefs_put_tracing_file(path); 100 | } else { 101 | /* The instance foo does not support trace options */ 102 | } 103 | 104 | ... 105 | 106 | if (tracefs_instance_is_new(inst)) 107 | tracefs_instance_destroy(inst); 108 | else 109 | tracefs_instance_free(inst); 110 | ... 111 | 112 | long long int res; 113 | if (tracefs_instance_file_read_number(NULL, "tracing_on", &res) == 0) { 114 | if (res == 0) { 115 | /* tracing is disabled in the top instance */ 116 | } else if (res == 1) { 117 | /* tracing is enabled in the top instance */ 118 | } else { 119 | /* Unknown tracing state of the top instance */ 120 | } 121 | } else { 122 | /* Failed to read integer from tracing_on file */ 123 | } 124 | 125 | ... 126 | 127 | int fd; 128 | fd = tracefs_instance_file_open(NULL, "tracing_on", O_WRONLY); 129 | if (fd >= 0) { 130 | /* Got file descriptor to the tracing_on file from the top instance for writing */ 131 | ... 132 | close(fd); 133 | } 134 | -- 135 | FILES 136 | ----- 137 | [verse] 138 | -- 139 | *tracefs.h* 140 | Header file to include in order to have access to the library APIs. 141 | *-ltracefs* 142 | Linker switch to add when building a program that uses the library. 143 | -- 144 | 145 | SEE ALSO 146 | -------- 147 | *libtracefs*(3), 148 | *libtraceevent*(3), 149 | *trace-cmd*(1) 150 | 151 | AUTHOR 152 | ------ 153 | [verse] 154 | -- 155 | *Steven Rostedt* 156 | *Tzvetomir Stoyanov* 157 | -- 158 | REPORTING BUGS 159 | -------------- 160 | Report bugs to 161 | 162 | LICENSE 163 | ------- 164 | libtracefs is Free Software licensed under the GNU LGPL 2.1 165 | 166 | RESOURCES 167 | --------- 168 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 169 | 170 | COPYING 171 | ------- 172 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 173 | the terms of the GNU Public License (GPL). 174 | -------------------------------------------------------------------------------- /Documentation/libtracefs-instances-manage.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_instance_create, tracefs_instance_destroy, tracefs_instance_alloc, tracefs_instance_free, 7 | tracefs_instance_is_new, tracefs_instances, tracefs_instance_clear, tracefs_instance_reset - Manage trace instances. 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | struct tracefs_instance pass:[*]*tracefs_instance_create*(const char pass:[*]_name_); 16 | int *tracefs_instance_destroy*(struct tracefs_instance pass:[*]_instance_); 17 | struct tracefs_instance pass:[*]*tracefs_instance_alloc*(const char pass:[*]_tracing_dir_, const char pass:[*]_name_); 18 | void *tracefs_instance_free*(struct tracefs_instance pass:[*]_instance_); 19 | bool *tracefs_instance_is_new*(struct tracefs_instance pass:[*]_instance_); 20 | char pass:[**]*tracefs_instances*(const char pass:[*]_regex_); 21 | void *tracefs_instance_clear*(struct tracefs_instance pass:[*]_instance_); 22 | void *tracefs_instance_reset*(struct tracefs_instance pass:[*]_instance_); 23 | 24 | -- 25 | 26 | DESCRIPTION 27 | ----------- 28 | This set of functions can be used to manage trace instances. A trace 29 | instance is a sub buffer used by the Linux tracing system. Given a unique 30 | name, the events enabled in an instance do not affect the main tracing 31 | system, nor other instances, as events enabled in the main tracing system 32 | or other instances do not affect the given instance. 33 | 34 | The *tracefs_instance_create()* function allocates and initializes a new 35 | tracefs_instance structure and returns it. If the instance with _name_ does 36 | not yet exist in the system, it will be created. The _name_ could be NULL, 37 | then the new tracefs_instance structure is initialized for the top instance. 38 | Note that the top instance cannot be created in the system, if it does not 39 | exist. 40 | 41 | The *tracefs_instance_destroy()* removes the instance from the system, but 42 | does not free the structure. *tracefs_instance_free()* must still be called 43 | on _instance_. 44 | 45 | The tracefs_instance_alloc()* function allocates a new tracefs_instance structure 46 | for existing trace instance. If the instance does not exist in the system, the function 47 | fails. The _tracing_dir_ parameter points to the system trace directory. It can be 48 | NULL, then default system trace directory is used. This parameter is useful to allocate 49 | instances to trace directories, copied from another machine. The _name_ is the name of 50 | the instance, or NULL for the top instance in the given _tracing_dir_. 51 | 52 | The *tracefs_instance_free()* function frees the tracefs_instance structure, 53 | without removing the trace instance from the system. 54 | 55 | The *tracefs_instance_is_new()* function checks if the given _instance_ is 56 | newly created by *tracefs_instance_create()*, or it has been in the system 57 | before that. 58 | 59 | The *tracefs_instances*() function returns a list of instances that exist in 60 | the system that match the regular expression _regex_. If _regex_ is NULL, then 61 | it will match all instances that exist. The returned list must be freed with 62 | *tracefs_list_free*(3). Note, if no instances are found an empty list is returned 63 | and that too needs to be free with *tracefs_list_free*(3). 64 | 65 | The *tracefs_instance_clear()* function clears the ring buffer of the given _instance_ 66 | or the top level ring buffer if _instance_ is NULL. 67 | 68 | The *tracefs_instance_reset*() function resets the given _instance_ to its default state. 69 | 70 | RETURN VALUE 71 | ------------ 72 | The *tracefs_instance_create()* and *tracefs_instance_alloc()* functions return a pointer to 73 | a newly allocated tracefs_instance structure. It must be freed with *tracefs_instance_free()*. 74 | 75 | The *tracefs_instance_destroy()* function returns 0 if it succeeds to remove 76 | the instance, otherwise it returns -1 if the instance does not exist or it 77 | fails to remove it. 78 | 79 | The *tracefs_instance_is_new()* function returns true if the 80 | *tracefs_instance_create()* that allocated _instance_ also created the 81 | trace instance in the system, or false if the trace instance already 82 | existed in the system when _instance_ was allocated by 83 | *tracefs_instance_create()* or *tracefs_instance_alloc()*. 84 | 85 | The *tracefs_instances()* returns a list of instance names that exist on the system. 86 | The list must be freed with *tracefs_list_free*(3). An empty list is returned if 87 | no instance exists that matches _regex_, and this needs to be freed with 88 | *tracefs_list_free*(3) as well. NULL is returned on error. 89 | 90 | The *tracefs_instance_clear()* returns 0 if it successfully cleared the ring buffer, 91 | or -1 on error. 92 | 93 | EXAMPLE 94 | ------- 95 | [source,c] 96 | -- 97 | #include 98 | 99 | struct tracefs_instance *inst = tracefs_instance_create("foo"); 100 | if (!inst) { 101 | /* Error creating a new trace instance */ 102 | ... 103 | } 104 | 105 | ... 106 | 107 | if (tracefs_instance_is_new(inst)) 108 | tracefs_instance_destroy(inst); 109 | tracefs_instance_free(inst); 110 | ... 111 | 112 | struct tracefs_instance *inst = tracefs_instance_alloc(NULL, "bar"); 113 | if (!inst) { 114 | /* Error allocating 'bar' trace instance */ 115 | ... 116 | } 117 | 118 | ... 119 | tracefs_instance_reset(inst); 120 | tracefs_instance_free(inst); 121 | -- 122 | FILES 123 | ----- 124 | [verse] 125 | -- 126 | *tracefs.h* 127 | Header file to include in order to have access to the library APIs. 128 | *-ltracefs* 129 | Linker switch to add when building a program that uses the library. 130 | -- 131 | 132 | SEE ALSO 133 | -------- 134 | *libtracefs*(3), 135 | *libtraceevent*(3), 136 | *trace-cmd*(1) 137 | 138 | AUTHOR 139 | ------ 140 | [verse] 141 | -- 142 | *Steven Rostedt* 143 | *Tzvetomir Stoyanov* 144 | -- 145 | REPORTING BUGS 146 | -------------- 147 | Report bugs to 148 | 149 | LICENSE 150 | ------- 151 | libtracefs is Free Software licensed under the GNU LGPL 2.1 152 | 153 | RESOURCES 154 | --------- 155 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 156 | 157 | COPYING 158 | ------- 159 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 160 | the terms of the GNU Public License (GPL). 161 | -------------------------------------------------------------------------------- /Documentation/libtracefs-instances-stat.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_instance_get_stat, tracefs_instance_put_stat, tracefs_buffer_stat_entries, tracefs_buffer_stat_overrun, 7 | tracefs_buffer_stat_commit_overrun, tracefs_buffer_stat_bytes, tracefs_buffer_stat_event_timestamp, 8 | tracefs_buffer_stat_timestamp, tracefs_buffer_stat_dropped_events, tracefs_buffer_stat_read_events 9 | - Handling tracing buffer stats 10 | 11 | SYNOPSIS 12 | -------- 13 | [verse] 14 | -- 15 | *#include * 16 | 17 | struct tracefs_buffer_stat pass:[*]*tracefs_instance_get_stat*(struct tracefs_instance pass:[*]_instance_, int _cpu_); 18 | void *tracefs_instance_put_stat*(struct tracefs_buffer_stat pass:[*]_tstat_); 19 | ssize_t *tracefs_buffer_stat_entries*(struct tracefs_buffer_stat pass:[*]_tstat_); 20 | ssize_t *tracefs_buffer_stat_overrun*(struct tracefs_buffer_stat pass:[*]_tstat_); 21 | ssize_t *tracefs_buffer_stat_commit_overrun*(struct tracefs_buffer_stat pass:[*]_tstat_); 22 | ssize_t *tracefs_buffer_stat_bytes*(struct tracefs_buffer_stat pass:[*]_tstat_); 23 | long long *tracefs_buffer_stat_event_timestamp*(struct tracefs_buffer_stat pass:[*]_tstat_); 24 | long long *tracefs_buffer_stat_timestamp*(struct tracefs_buffer_stat pass:[*]_tstat_); 25 | ssize_t *tracefs_buffer_stat_dropped_events*(struct tracefs_buffer_stat pass:[*]_tstat_); 26 | ssize_t *tracefs_buffer_stat_read_events*(struct tracefs_buffer_stat pass:[*]_tstat_); 27 | -- 28 | 29 | DESCRIPTION 30 | ----------- 31 | This set of functions read and parse the tracefs/per_cpu/cpuX/stats file. 32 | These files hold the statistics of the per CPU ring buffer, such as how 33 | many events are in the ring buffer, how many have been read and so on. 34 | 35 | The *tracefs_instance_get_stat()* function will read and parse a given statistics 36 | file for a given _instance_ and _cpu_. As the ring buffer is split into per_cpu buffers, 37 | the information is only associated to the given _cpu_. The returned tracefs_buffer_stat 38 | pointer can be used with the other *tracefs_buffer_stat* functions and must be freed with 39 | *tracefs_instance_put_stat()*. 40 | 41 | The *tracefs_instance_put_stat()* will free the resources allocated for the given _stat_ 42 | that was created by *tracefs_instance_get_stat()*. 43 | 44 | The *tracefs_buffer_stat_entries()* returns the number of events that are currently 45 | in the ring buffer associated with _tstat_. 46 | 47 | The *tracefs_buffer_stat_overrun()* returns the number of events that were lost by 48 | the ring buffer writer overrunning the reader. 49 | 50 | The *tracefs_buffer_stat_commit_overrun()* returns the number of events that were 51 | lost because the ring buffer was too small and an interrupt interrupted a lower 52 | context event being recorded and it added more events than the ring buffer could 53 | hold. Note this is not a common occurrence and when it happens it means that 54 | something was not set up properly. 55 | 56 | The *tracefs_buffer_stat_bytes()* returns the number of bytes that the current events 57 | take up. Note, it includes the meta data for the events, but does not include the 58 | meta data for the sub-buffers. 59 | 60 | The *tracefs_buffer_stat_event_timestamp()* returns the timestamp of the last event in the 61 | ring buffer. 62 | 63 | The *tracefs_buffer_stat_timestamp()* returns the current timestamp of the ring buffer. 64 | Note, it is only read when *tracefs_instance_get_stat()* is called. It will have the 65 | timestamp of the ring buffer when that function was called. 66 | 67 | The *tracefs_buffer_stat_dropped_events()* returns the number of events that were 68 | dropped if overwrite mode is disabled. It will show the events that were lost because 69 | the writer caught up to the reader and could not write any more events. 70 | 71 | The *tracefs_buffer_stat_read_events()* returns the number of events that were consumed 72 | by a reader. 73 | 74 | 75 | RETURN VALUE 76 | ------------ 77 | The *tracefs_instance_get_stat()* returns a tracefs_buffer_stat structure that can 78 | be used to retrieve the statistics via the other functions. It must be freed with 79 | *tracefs_instance_put_stat()*. 80 | 81 | The other functions that return different values from the tracefs_buffer_stat structure 82 | all return the value, or -1 if the value was not found. 83 | 84 | 85 | EXAMPLE 86 | ------- 87 | [source,c] 88 | -- 89 | #include 90 | #include 91 | #include 92 | 93 | int main(int argc, char **argv) 94 | { 95 | char *trace; 96 | char buf[1000]; 97 | int ret; 98 | int i; 99 | 100 | for (i = 0; i < sizeof(buf) - 1; i++) { 101 | buf[i] = '0' + i % 10; 102 | } 103 | buf[i] = '\0'; 104 | 105 | tracefs_instance_clear(NULL); 106 | 107 | for (i = 0; i < 4; i++) { 108 | ret = tracefs_printf(NULL, "%s\n", buf); 109 | if (ret < 0) 110 | perror("write"); 111 | } 112 | 113 | trace = tracefs_instance_file_read(NULL, "trace", NULL); 114 | printf("%s\n", trace); 115 | free(trace); 116 | 117 | for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) { 118 | struct tracefs_buffer_stat *tstat; 119 | ssize_t entries, eread; 120 | 121 | tstat = tracefs_instance_get_stat(NULL, i); 122 | if (!tstat) 123 | continue; 124 | 125 | entries = tracefs_buffer_stat_entries(tstat); 126 | eread = tracefs_buffer_stat_read_events(tstat); 127 | if (!entries && !eread) { 128 | tracefs_instance_put_stat(tstat); 129 | continue; 130 | } 131 | 132 | printf("CPU: %d\n", i);; 133 | printf("\tentries: %zd\n", entries); 134 | printf("\toverrun: %zd\n", tracefs_buffer_stat_overrun(tstat)); 135 | printf("\tcommit_overrun: %zd\n", tracefs_buffer_stat_commit_overrun(tstat)); 136 | printf("\tbytes: %zd\n", tracefs_buffer_stat_bytes(tstat)); 137 | printf("\tevent_timestamp: %lld\n", tracefs_buffer_stat_event_timestamp(tstat)); 138 | printf("\ttimestamp: %lld\n", tracefs_buffer_stat_timestamp(tstat)); 139 | printf("\tdropped_events: %zd\n", tracefs_buffer_stat_dropped_events(tstat)); 140 | printf("\tread_events: %zd\n", eread); 141 | 142 | tracefs_instance_put_stat(tstat); 143 | } 144 | } 145 | -- 146 | FILES 147 | ----- 148 | [verse] 149 | -- 150 | *tracefs.h* 151 | Header file to include in order to have access to the library APIs. 152 | *-ltracefs* 153 | Linker switch to add when building a program that uses the library. 154 | -- 155 | 156 | SEE ALSO 157 | -------- 158 | *libtracefs*(3), 159 | *libtraceevent*(3), 160 | *trace-cmd*(1) 161 | 162 | AUTHOR 163 | ------ 164 | [verse] 165 | -- 166 | *Steven Rostedt* 167 | -- 168 | REPORTING BUGS 169 | -------------- 170 | Report bugs to 171 | 172 | LICENSE 173 | ------- 174 | libtracefs is Free Software licensed under the GNU LGPL 2.1 175 | 176 | RESOURCES 177 | --------- 178 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 179 | 180 | COPYING 181 | ------- 182 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 183 | the terms of the GNU Public License (GPL). 184 | -------------------------------------------------------------------------------- /Documentation/libtracefs-instances-subbuf.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_instance_get_subbuf_size, tracefs_instance_set_subbuf_size - Helper functions for working with ring buffer sub buffers. 7 | 8 | SYNOPSIS 9 | -------- 10 | [verse] 11 | -- 12 | *#include * 13 | 14 | size_t *tracefs_instance_get_subbuf_size*(struct tracefs_instance pass:[*]_instance_); 15 | int *tracefs_instance_set_subbuf_size*(struct tracefs_instance pass:[*]_instance_, size_t _size_); 16 | -- 17 | 18 | DESCRIPTION 19 | ----------- 20 | Helper functions for working with the sub-buffers of the tracing ring buffer. 21 | The tracing ring buffer is broken up into *sub-buffers*. An event can not be 22 | bigger than the data section of the sub-buffer (see *tep_get_sub_buffer_data_size*(3)). 23 | By default, the ring buffer uses the architectures *page_size* as the default 24 | size of the sub-buffer, but this can be limiting if there is a need for large 25 | events, for example, the application wants to write large strings into 26 | the trace_marker file. 27 | 28 | The *tracefs_instance_get_subbuf_size()* returns the current size in kilobytes 29 | fo the ring buffer sub-buffers. 30 | 31 | The *tracefs_instance_set_subbuf_size()* will write the size in kilobytes of 32 | what the new sub-buffer size should be. Note, that this is only a hint to what 33 | the minimum sub-buffer size should be. It also does not take into account the 34 | meta-data that is used by the sub-buffer, so the size written should be no less 35 | than 16 bytes more than the maximum event size that will be used. The kernel 36 | will likely make the sub-buffer size larger than specified, as it may need to 37 | align the size for implementation purposes. 38 | 39 | RETURN VALUE 40 | ------------ 41 | The *tracefs_instance_get_subbuf_size()* returns the size of the current 42 | sub-buffer for the given _instance_ ring buffer or -1 on error. 43 | 44 | The *tracefs_instance_set_subbuf_size()* will return 0 if it successfully set 45 | the _instance_ ring buffer sub-buffer size in kilobytes, or -1 on error. 46 | 47 | EXAMPLE 48 | ------- 49 | [source,c] 50 | -- 51 | #include 52 | #include 53 | #include 54 | 55 | int main(int argc, char **argv) 56 | { 57 | struct tep_handle *tep; 58 | ssize_t save_subsize; 59 | ssize_t subsize; 60 | char *trace; 61 | char buf[3000]; 62 | int meta_size; 63 | int ret; 64 | int i; 65 | 66 | tep = tep_alloc(); 67 | ret = tracefs_load_headers(NULL, tep); 68 | tep_free(tep); 69 | 70 | if (ret < 0) { 71 | perror("reading headers"); 72 | exit(-1); 73 | } 74 | 75 | meta_size = tep_get_sub_buffer_size(tep) - tep_get_sub_buffer_data_size(tep); 76 | 77 | save_subsize = tracefs_instance_get_subbuf_size(NULL); 78 | if (save_subsize < 0) { 79 | printf("Changing sub-buffer size not available\n"); 80 | exit(-1); 81 | } 82 | 83 | subsize = save_subsize * 1024; 84 | 85 | /* Have at least 4 writes fit on a sub-buffer */ 86 | if (subsize - meta_size < sizeof(buf) *4 ) { 87 | subsize = ((sizeof(buf) * 4 + meta_size) + 1023) / 1024; 88 | tracefs_instance_set_subbuf_size(NULL, subsize); 89 | } 90 | 91 | for (i = 0; i < sizeof(buf) - 1; i++) { 92 | buf[i] = '0' + i % 10; 93 | } 94 | buf[i] = '\0'; 95 | 96 | tracefs_instance_clear(NULL); 97 | 98 | for (i = 0; i < 4; i++) { 99 | ret = tracefs_printf(NULL, "%s\n", buf); 100 | if (ret < 0) 101 | perror("write"); 102 | } 103 | 104 | trace = tracefs_instance_file_read(NULL, "trace", NULL); 105 | printf("%s\n", trace); 106 | free(trace); 107 | 108 | printf("Buffer size was: %zd * 1024\n", 109 | tracefs_instance_get_subbuf_size(NULL)); 110 | 111 | tracefs_instance_set_subbuf_size(NULL, save_subsize); 112 | } 113 | -- 114 | FILES 115 | ----- 116 | [verse] 117 | -- 118 | *tracefs.h* 119 | Header file to include in order to have access to the library APIs. 120 | *-ltracefs* 121 | Linker switch to add when building a program that uses the library. 122 | -- 123 | 124 | SEE ALSO 125 | -------- 126 | *libtracefs*(3), 127 | *libtraceevent*(3), 128 | *trace-cmd*(1) 129 | 130 | AUTHOR 131 | ------ 132 | [verse] 133 | -- 134 | *Steven Rostedt* 135 | *Tzvetomir Stoyanov* 136 | -- 137 | REPORTING BUGS 138 | -------------- 139 | Report bugs to 140 | 141 | LICENSE 142 | ------- 143 | libtracefs is Free Software licensed under the GNU LGPL 2.1 144 | 145 | RESOURCES 146 | --------- 147 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 148 | 149 | COPYING 150 | ------- 151 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 152 | the terms of the GNU Public License (GPL). 153 | -------------------------------------------------------------------------------- /Documentation/libtracefs-instances-utils.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_instance_get_name, tracefs_instance_get_trace_dir, tracefs_instances_walk, tracefs_instance_exists, 7 | tracefs_instance_get_buffer_size, tracefs_instance_set_buffer_size, tracefs_instance_get_buffer_percent, 8 | tracefs_instance_set_buffer_percent - Helper functions for working with tracing instances. 9 | 10 | SYNOPSIS 11 | -------- 12 | [verse] 13 | -- 14 | *#include * 15 | 16 | const char pass:[*]*tracefs_instance_get_name*(struct tracefs_instance pass:[*]_instance_); 17 | const char pass:[*]*tracefs_instance_get_trace_dir*(struct tracefs_instance pass:[*]_instance_); 18 | int *tracefs_instances_walk*(int (pass:[*]_callback_)(const char pass:[*], void pass:[*]), void pass:[*]_context)_; 19 | bool *tracefs_instance_exists*(const char pass:[*]_name_); 20 | size_t *tracefs_instance_get_buffer_size*(struct tracefs_instance pass:[*]_instance_, int _cpu_); 21 | int *tracefs_instance_set_buffer_size*(struct tracefs_instance pass:[*]_instance_, size_t _size_, int _cpu_); 22 | int *tracefs_instance_get_buffer_percent*(struct tracefs_instance pass:[*]_instance_); 23 | int *tracefs_instance_set_buffer_percent*(struct tracefs_instance pass:[*]_instance_, int _val_); 24 | -- 25 | 26 | DESCRIPTION 27 | ----------- 28 | Helper functions for working with trace instances. 29 | 30 | The *tracefs_instance_get_name()* function returns the name of the given _instance_. 31 | Note that the top instance has no name, the function returns NULL for it. 32 | 33 | The *tracefs_instance_get_trace_dir()* function returns the tracing directory, where 34 | the given _instance_ is configured. 35 | 36 | The *tracefs_instances_walk()* function walks through all configured tracing 37 | instances in the system and calls _callback_ for each one of them. The _context_ 38 | argument is passed to the _callback_, together with the instance name. If the 39 | _callback_ returns non-zero, the iteration stops. Note, the _callback_ is not 40 | called for the top top instance. 41 | 42 | The *tracefs_instance_exists()* function checks if an instance with the given 43 | _name_ exists in the system. 44 | 45 | The *tracefs_instace_get_buffer_size()* returns the size of the ring buffer. If _cpu_ 46 | is negative, it returns the total size of all the per CPU ring buffers, otherwise 47 | it returns the size of the per CPU ring buffer for _cpu_. 48 | 49 | The *tracefs_instance_set_buffer_size()* function sets the size of the ring buffer. 50 | If _cpu_ is negative, then it sets all the per CPU ring buffers to _size_ (note 51 | the total size is the number of CPUs * _size_). If _cpu_ is specified, then it only 52 | sets the size of the per CPU ring buffer. 53 | 54 | The *tracefs_instance_set_buffer_percent()* sets the buffer percent value of 55 | the tracing ring buffer for _instance_ or the top level buffer if _instance_ is 56 | NULL. The buffer percent decides when readers on *tracefs_cpu_read*(3), 57 | *tracefs_cpu_buffered_read*(3), *tracefs_cpu_write*(3) and *tracefs_cpu_pipe*(3) 58 | will block when O_NONBLOCK is not set. The value of _val_ must be between 0 and 59 | 100, where: 60 | 61 | [verse] 62 | -- 63 | 0 - block until there's any data in the ring buffer 64 | 1 - block until 1% of the ring buffer sub-buffers are filled 65 | 50 - block until 50% of the ring buffer sub-buffers are filled 66 | 100 - block until the entire ring buffer is filled 67 | -- 68 | 69 | Note, any number from 0 to 100 can be used where it is the percentage of the 70 | ring buffer that must be filled before a blocked reader will be notified that 71 | there's data to be retrieved. 72 | 73 | The *tracefs_instance_get_buffer_percent()* retrieves the current buffer percent 74 | setting of the tracing ring buffer for _instance_ or the top level buffer 75 | if _instance_ is NULL. 76 | 77 | RETURN VALUE 78 | ------------ 79 | The *tracefs_instance_get_name()* returns a string or NULL in case of the top 80 | instance. The returned string must _not_ be freed. 81 | 82 | The *tracefs_instance_get_trace_dir()* returns a string or NULL in case of an error. 83 | The returned string must _not_ be freed. 84 | 85 | The *tracefs_instances_walk()* function returns 0, if all instances were iterated, 1 86 | if the iteration was stopped by the _callback_, or -1 in case of an error. 87 | 88 | The *tracefs_instance_exists()* returns true if an instance with the given _name_ 89 | exists in the system or false otherwise. 90 | 91 | The *tracefs_instance_get_buffer_size()* returns the size of the ring buffer depending on 92 | the _cpu_ value passed in, or -1 on error. 93 | 94 | The *tracefs_instance_set_buffer_size()* returns zero on success and -1 on error. 95 | 96 | EXAMPLE 97 | ------- 98 | [source,c] 99 | -- 100 | #include 101 | 102 | struct tracefs_instance *inst; 103 | .... 104 | char *name = tracefs_instance_get_name(inst); 105 | if(name) { 106 | /* Got name of the instance */ 107 | } 108 | char *dir = tracefs_instance_get_trace_dir(inst); 109 | if(dir) { 110 | /* Got tracing directory of the instance */ 111 | } 112 | ... 113 | static int instance_walk(char *name, void *context) 114 | { 115 | /* Got instance with name */ 116 | return 0; 117 | } 118 | ... 119 | if (tracefs_instances_walk(instance_walk, NULL) < 0) { 120 | /* Error walking through the instances */ 121 | } 122 | ... 123 | if (tracefs_instance_exists("foo")) { 124 | /* There is instance with name foo in the system */ 125 | } else { 126 | /* There is no instance with name foo in the system */ 127 | } 128 | -- 129 | FILES 130 | ----- 131 | [verse] 132 | -- 133 | *tracefs.h* 134 | Header file to include in order to have access to the library APIs. 135 | *-ltracefs* 136 | Linker switch to add when building a program that uses the library. 137 | -- 138 | 139 | SEE ALSO 140 | -------- 141 | *libtracefs*(3), 142 | *libtraceevent*(3), 143 | *trace-cmd*(1) 144 | 145 | AUTHOR 146 | ------ 147 | [verse] 148 | -- 149 | *Steven Rostedt* 150 | *Tzvetomir Stoyanov* 151 | -- 152 | REPORTING BUGS 153 | -------------- 154 | Report bugs to 155 | 156 | LICENSE 157 | ------- 158 | libtracefs is Free Software licensed under the GNU LGPL 2.1 159 | 160 | RESOURCES 161 | --------- 162 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 163 | 164 | COPYING 165 | ------- 166 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 167 | the terms of the GNU Public License (GPL). 168 | -------------------------------------------------------------------------------- /Documentation/libtracefs-log.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_set_loglevel - Set log level of the library 7 | 8 | SYNOPSIS 9 | -------- 10 | [verse] 11 | -- 12 | *#include * 13 | 14 | int *tracefs_set_loglevel*(enum tep_loglevel _level_); 15 | -- 16 | 17 | DESCRIPTION 18 | ----------- 19 | The *tracefs_set_loglevel()* function sets the level of the library logs that will be printed on 20 | the console. See _libtraceevent(3)_ for detailed description of the log levels. Setting the log 21 | level to specific value means that logs from the previous levels will be printed too. For example 22 | _TEP_LOG_WARNING_ will print any logs with severity _TEP_LOG_WARNING_, _TEP_LOG_ERROR_ and 23 | _TEP_LOG_CRITICAL_. The default log level is _TEP_LOG_CRITICAL_. When a new level is set, it is 24 | also propagated to the libtraceevent. 25 | 26 | EXAMPLE 27 | ------- 28 | [source,c] 29 | -- 30 | #include 31 | 32 | tracefs_set_loglevel(TEP_LOG_ALL); 33 | ... 34 | /* call libtracefs or libtraceevent APIs and observe any logs they produce */ 35 | ... 36 | tracefs_set_loglevel(TEP_LOG_CRITICAL); 37 | -- 38 | FILES 39 | ----- 40 | [verse] 41 | -- 42 | *tracefs.h* 43 | Header file to include in order to have access to the library APIs. 44 | *-ltracefs* 45 | Linker switch to add when building a program that uses the library. 46 | -- 47 | 48 | SEE ALSO 49 | -------- 50 | *libtracefs*(3), 51 | *libtraceevent*(3), 52 | *trace-cmd*(1) 53 | 54 | AUTHOR 55 | ------ 56 | [verse] 57 | -- 58 | *Steven Rostedt* 59 | *Tzvetomir Stoyanov* 60 | -- 61 | REPORTING BUGS 62 | -------------- 63 | Report bugs to 64 | 65 | LICENSE 66 | ------- 67 | libtracefs is Free Software licensed under the GNU LGPL 2.1 68 | 69 | RESOURCES 70 | --------- 71 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 72 | 73 | COPYING 74 | ------- 75 | Copyright \(C) 2021 VMware, Inc. Free use of this software is granted under 76 | the terms of the GNU Public License (GPL). 77 | -------------------------------------------------------------------------------- /Documentation/libtracefs-marker.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_print_init, tracefs_print_close, tracefs_printf, tracefs_vprintf - 7 | Open, close and write formated strings in the trace buffer. 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | int *tracefs_print_init*(struct tracefs_instance pass:[*]_instance_); 16 | int *tracefs_printf*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_fmt_, _..._); 17 | int *tracefs_vprintf*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_fmt_, va_list _ap_); 18 | void *tracefs_print_close*(struct tracefs_instance pass:[*]_instance_); 19 | 20 | -- 21 | 22 | DESCRIPTION 23 | ----------- 24 | Set of functions to write formated strings in the trace buffer. 25 | See Documentation/trace/ftrace.rst from the Linux kernel tree for more information about writing 26 | data from user space in the trace buffer. All these APIs have _instance_ as a first argument. If 27 | NULL is passed as _instance_, the top trace instance is used. 28 | 29 | The *tracefs_print_init()* function initializes the library for writing into the trace buffer of 30 | the selected _instance_. It is not mandatory to call this API before writing strings, any of 31 | the printf APIs will call it automatically, if the library is not yet initialized. But calling 32 | *tracefs_print_init()* in advance will speed up the writing. 33 | 34 | The *tracefs_printf()* function writes a formatted string in the trace buffer of the selected 35 | _instance_. The _fmt_ argument is a string in printf format, followed by variable arguments _..._. 36 | 37 | The *tracefs_vprintf()* function writes a formatted string in the trace buffer of the selected 38 | _instance_. The _fmt_ argument is a string in printf format, followed by list _ap_ of arguments. 39 | 40 | The *tracefs_print_close()* function closes the resources, used by the library for writing in 41 | the trace buffer of the selected instance. 42 | 43 | RETURN VALUE 44 | ------------ 45 | The *tracefs_print_init()*, *tracefs_printf()*, and *tracefs_vprintf()* functions return 0 if 46 | the operation is successful, or -1 in case of an error. 47 | 48 | EXAMPLE 49 | ------- 50 | [source,c] 51 | -- 52 | #include 53 | 54 | if (tracefs_print_init(NULL) < 0) { 55 | /* Failed to initialize the library for writing in the trace buffer of the top trace instance */ 56 | } 57 | 58 | void foo_print(char *format, ...) 59 | { 60 | va_list ap; 61 | va_start(ap, format); 62 | if (tracefs_vprintf(NULL, format, ap) < 0) { 63 | /* Failed to print in the trace buffer */ 64 | } 65 | va_end(ap); 66 | } 67 | 68 | void foo_print_string(char *message) 69 | { 70 | if (tracefs_printf(NULL, "Message from user space: %s", message) < 0) { 71 | /* Failed to print in the trace buffer */ 72 | } 73 | } 74 | 75 | tracefs_print_close(); 76 | -- 77 | FILES 78 | ----- 79 | [verse] 80 | -- 81 | *tracefs.h* 82 | Header file to include in order to have access to the library APIs. 83 | *-ltracefs* 84 | Linker switch to add when building a program that uses the library. 85 | -- 86 | 87 | SEE ALSO 88 | -------- 89 | *libtracefs*(3), 90 | *libtraceevent*(3), 91 | *trace-cmd*(1), 92 | Documentation/trace/ftrace.rst from the Linux kernel tree 93 | 94 | AUTHOR 95 | ------ 96 | [verse] 97 | -- 98 | *Steven Rostedt* 99 | *Tzvetomir Stoyanov* 100 | -- 101 | REPORTING BUGS 102 | -------------- 103 | Report bugs to 104 | 105 | LICENSE 106 | ------- 107 | libtracefs is Free Software licensed under the GNU LGPL 2.1 108 | 109 | RESOURCES 110 | --------- 111 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 112 | 113 | COPYING 114 | ------- 115 | Copyright \(C) 2021 VMware, Inc. Free use of this software is granted under 116 | the terms of the GNU Public License (GPL). 117 | -------------------------------------------------------------------------------- /Documentation/libtracefs-marker_raw.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_binary_init, tracefs_binary_close, tracefs_binary_write - 7 | Open, close and write binary data in the trace buffer. 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | int *tracefs_binary_init*(struct tracefs_instance pass:[*]_instance_); 16 | int *tracefs_binary_write*(struct tracefs_instance pass:[*]_instance_, void pass:[*]_data_, int _len_); 17 | void *tracefs_binary_close*(struct tracefs_instance pass:[*]_instance_); 18 | 19 | -- 20 | 21 | DESCRIPTION 22 | ----------- 23 | Set of functions to write binary data in the trace buffer. 24 | See Documentation/trace/ftrace.rst from the Linux kernel tree for more information about writing 25 | data from user space in the trace buffer. All these APIs have _instance_ as a first argument. If 26 | NULL is passed as _instance_, the top trace instance is used. 27 | 28 | The *tracefs_binary_init()* function initializes the library for writing into the trace buffer of 29 | the selected _instance_. It is not mandatory to call this API before writing data, the 30 | *tracefs_binary_write()* will call it automatically, if the library is not yet initialized. 31 | But calling *tracefs_binary_init()* in advance will speed up the writing. 32 | 33 | The *tracefs_binary_write()* function writes a binary data in the trace buffer of the selected 34 | _instance_. The _data_ points to the data with length _len_, that is going to be written in 35 | the trace buffer. 36 | 37 | The *tracefs_binary_close()* function closes the resources, used by the library for writing in 38 | the trace buffer of the selected instance. 39 | 40 | RETURN VALUE 41 | ------------ 42 | The *tracefs_binary_init()*, and *tracefs_binary_write()* functions return 0 if the operation is 43 | successful, or -1 in case of an error. 44 | 45 | EXAMPLE 46 | ------- 47 | [source,c] 48 | -- 49 | #include 50 | 51 | if (tracefs_binary_init(NULL) < 0) { 52 | /* Failed to initialize the library for writing in the trace buffer of the top trace instance */ 53 | } 54 | 55 | unsigned int data = 0xdeadbeef; 56 | 57 | if (tracefs_binary_write(NULL, &data, sizeof(data)) < 0) { 58 | /* Failed to write in the trace buffer */ 59 | } 60 | 61 | tracefs_binary_close(); 62 | -- 63 | FILES 64 | ----- 65 | [verse] 66 | -- 67 | *tracefs.h* 68 | Header file to include in order to have access to the library APIs. 69 | *-ltracefs* 70 | Linker switch to add when building a program that uses the library. 71 | -- 72 | 73 | SEE ALSO 74 | -------- 75 | *libtracefs*(3), 76 | *libtraceevent*(3), 77 | *trace-cmd*(1), 78 | Documentation/trace/ftrace.rst from the Linux kernel tree 79 | 80 | AUTHOR 81 | ------ 82 | [verse] 83 | -- 84 | *Steven Rostedt* 85 | *Tzvetomir Stoyanov* 86 | -- 87 | REPORTING BUGS 88 | -------------- 89 | Report bugs to 90 | 91 | LICENSE 92 | ------- 93 | libtracefs is Free Software licensed under the GNU LGPL 2.1 94 | 95 | RESOURCES 96 | --------- 97 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 98 | 99 | COPYING 100 | ------- 101 | Copyright \(C) 2021 VMware, Inc. Free use of this software is granted under 102 | the terms of the GNU Public License (GPL). 103 | -------------------------------------------------------------------------------- /Documentation/libtracefs-option-get.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_options_get_supported, tracefs_option_is_supported, tracefs_options_get_enabled, 7 | tracefs_option_is_enabled, tracefs_option_mask_is_set, tracefs_option_id 8 | - Get and check ftrace options. 9 | 10 | SYNOPSIS 11 | -------- 12 | [verse] 13 | -- 14 | *#include * 15 | 16 | const struct tracefs_options_mask pass:[*]*tracefs_options_get_supported*(struct tracefs_instance pass:[*]_instance_); 17 | bool *tracefs_option_is_supported*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_); 18 | const struct tracefs_options_mask pass:[*]*tracefs_options_get_enabled*(struct tracefs_instance pass:[*]_instance_); 19 | bool *tracefs_option_is_enabled*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_); 20 | bool *tracefs_option_mask_is_set*(const struct tracefs_options_mask *options, enum tracefs_option_id id); 21 | enum tracefs_option_id *tracefs_option_id*(const char pass:[*]_name_); 22 | -- 23 | 24 | DESCRIPTION 25 | ----------- 26 | This set of APIs can be used to get and check current ftrace options. Supported ftrace options may 27 | depend on the kernel version and the kernel configuration. 28 | 29 | The *tracefs_options_get_supported()* function gets all ftrace options supported by the system in 30 | the given _instance_. If _instance_ is NULL, supported options of the top trace instance are 31 | returned. The set of supported options is the same in all created trace instances, but may be different 32 | than the top trace instance. 33 | 34 | The *tracefs_option_is_supported()/ function checks if the option with given _id_ is supported by 35 | the system in the given _instance_. If _instance_ is NULL, the top trace instance is used. If an 36 | option is supported at the top trace instance, it it may not be supported in a created trace instance. 37 | 38 | The *tracefs_options_get_enabled()* function gets all ftrace options, currently enabled in 39 | the given _instance_. If _instance_ is NULL, enabled options of the top trace instance are returned. 40 | 41 | The *tracefs_option_is_enabled()* function checks if the option with given _id_ is enabled in the 42 | given _instance_. If _instance_ is NULL, the top trace instance is used. 43 | 44 | The *tracefs_option_mask_is_set()* function checks if the bit, corresponding to the option with _id_ is 45 | set in the _options_ bitmask returned from *tracefs_option_get_enabled()* and *tracefs_option_is_supported()*. 46 | 47 | The *tracefs_option_id()* converts an option _name_ into its corresponding id, if it is found. 48 | This allows to find the option _id_ to use in the other functions if only the _name_ is known. 49 | 50 | RETURN VALUE 51 | ------------ 52 | The *tracefs_options_get_supported()* and *tracefs_options_get_enabled()* functions, on success, 53 | return a pointer to the bitmask within the instance, or a global bitmask for the top level, 54 | or NULL in case of an error. As the returned bitmask is part of the instance structure (or a 55 | global variable) and must not be freed or modified. 56 | 57 | The *tracefs_option_is_supported()* and *tracefs_option_is_enabled()* functions return true if the 58 | option in supported / enabled, or false otherwise. 59 | 60 | The *tracefs_option_mask_is_set()* returns true if the corresponding option is set in the mask 61 | or false otherwise. 62 | 63 | The *tracefs_option_id()* returns the corresponding id defined by *tracefs_options*(3) from 64 | the given _name_. If the _name_ can not be found, then TRACEFS_OPTION_INVALID is returned. 65 | 66 | EXAMPLE 67 | ------- 68 | [source,c] 69 | -- 70 | #include 71 | ... 72 | const struct tracefs_options_mask *options; 73 | ... 74 | options = tracefs_options_get_supported(NULL); 75 | if (!options) { 76 | /* Failed to get supported options */ 77 | } else { 78 | ... 79 | } 80 | ... 81 | options = tracefs_options_get_enabled(NULL); 82 | if (!options) { 83 | /* Failed to get options, enabled in the top instance */ 84 | } else { 85 | ... 86 | } 87 | if (tracefs_options_mask_is_set(options, TRACEFS_OPTION_LATENCY_FORMAT)) { 88 | ... 89 | } 90 | ... 91 | 92 | if (tracefs_option_is_supported(NULL, TRACEFS_OPTION_LATENCY_FORMAT)) { 93 | /* Latency format option is supprted */ 94 | } 95 | 96 | ... 97 | 98 | if (tracefs_option_is_enabled(NULL, TRACEFS_OPTION_STACKTRACE)) { 99 | /* Stacktrace option is enabled in the top instance */ 100 | } 101 | 102 | -- 103 | FILES 104 | ----- 105 | [verse] 106 | -- 107 | *tracefs.h* 108 | Header file to include in order to have access to the library APIs. 109 | *-ltracefs* 110 | Linker switch to add when building a program that uses the library. 111 | -- 112 | 113 | SEE ALSO 114 | -------- 115 | *libtracefs*(3), 116 | *libtraceevent*(3), 117 | *trace-cmd*(1) 118 | 119 | AUTHOR 120 | ------ 121 | [verse] 122 | -- 123 | *Steven Rostedt* 124 | *Tzvetomir Stoyanov* 125 | -- 126 | REPORTING BUGS 127 | -------------- 128 | Report bugs to 129 | 130 | LICENSE 131 | ------- 132 | libtracefs is Free Software licensed under the GNU LGPL 2.1 133 | 134 | RESOURCES 135 | --------- 136 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 137 | 138 | COPYING 139 | ------- 140 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 141 | the terms of the GNU Public License (GPL). 142 | -------------------------------------------------------------------------------- /Documentation/libtracefs-option-misc.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_option_enable, tracefs_option_disable, tracefs_option_name - 7 | Various trace option functions. 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | int *tracefs_option_enable*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_); 16 | int *tracefs_option_disable*(struct tracefs_instance pass:[*]_instance_, enum tracefs_option_id _id_); 17 | const char pass:[*]*tracefs_option_name*(enum tracefs_option_id _id_); 18 | -- 19 | 20 | DESCRIPTION 21 | ----------- 22 | This set of APIs can be used to enable and disable ftrace options and to get the name of an option. 23 | 24 | The *tracefs_option_enable()* function enables the option with _id_ in the given _instance_. If 25 | _instance_ is NULL, the option is enabled in the top trace instance. 26 | 27 | The *tracefs_option_disable()* function disables the option with _id_ in the given _instance_. If 28 | _instance_ is NULL, the option is disabled in the top trace instance. 29 | 30 | The *tracefs_option_name()* function returns a string, representing the option with _id_. The string 31 | must *not* be freed. 32 | 33 | 34 | RETURN VALUE 35 | ------------ 36 | The *tracefs_option_enable()* and *tracefs_option_disable()* functions return 0 if the state of the 37 | option is set successfully, or -1 in case of an error. 38 | 39 | The *tracefs_option_name()* function returns string with option name, or "unknown" in case of an 40 | error. The returned string must *not* be freed. 41 | 42 | EXAMPLE 43 | ------- 44 | [source,c] 45 | -- 46 | #include 47 | ... 48 | if (tracefs_option_enable(NULL, TRACEFS_OPTION_ANNOTATE)) { 49 | /* Failed to enable annotate option in top trace instance */ 50 | } 51 | ... 52 | if (tracefs_option_disable(NULL, TRACEFS_OPTION_CONTEXT_INFO)) { 53 | /* Failed to disable context info option in top trace instance */ 54 | } 55 | ... 56 | char *name = tracefs_option_name(TRACEFS_OPTION_FUNC_STACKTRACE); 57 | if (strcmp(name, "unknown")) { 58 | /* Cannot get the name of the option */ 59 | } 60 | 61 | -- 62 | FILES 63 | ----- 64 | [verse] 65 | -- 66 | *tracefs.h* 67 | Header file to include in order to have access to the library APIs. 68 | *-ltracefs* 69 | Linker switch to add when building a program that uses the library. 70 | -- 71 | 72 | SEE ALSO 73 | -------- 74 | *libtracefs*(3), 75 | *libtraceevent*(3), 76 | *trace-cmd*(1) 77 | 78 | AUTHOR 79 | ------ 80 | [verse] 81 | -- 82 | *Steven Rostedt* 83 | *Tzvetomir Stoyanov* 84 | -- 85 | REPORTING BUGS 86 | -------------- 87 | Report bugs to 88 | 89 | LICENSE 90 | ------- 91 | libtracefs is Free Software licensed under the GNU LGPL 2.1 92 | 93 | RESOURCES 94 | --------- 95 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 96 | 97 | COPYING 98 | ------- 99 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 100 | the terms of the GNU Public License (GPL). 101 | -------------------------------------------------------------------------------- /Documentation/libtracefs-snapshot.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_snapshot_snap, tracefs_snapshot_clear, tracefs_snapshot_free - 7 | API to create, clear and read snapshots 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | int *tracefs_snapshot_snap*(struct tracefs_instance pass:[*]instance); 16 | int *tracefs_snapshot_clear*(struct tracefs_instance pass:[*]instance); 17 | int *tracefs_snapshot_free*(struct tracefs_instance pass:[*]instance); 18 | -- 19 | 20 | DESCRIPTION 21 | ----------- 22 | The Linux kernel tracing provides a "snapshot" feature. The kernel has two 23 | ring buffers. One that is written to by the tracing system and another one that 24 | is the "snapshot" buffer. When a snapshot happens, the two buffers are swapped, and 25 | the current snapshot buffer becomes the one being written to, and the buffer 26 | that was being written to becomes the saved snapshot. 27 | 28 | Note, the snapshot buffer is allocated the first time it is taken, so it is best 29 | to take a snapshot at the start before one is needed so that it is allocated 30 | and a snapshot is ready, then the snapshot will happen immediately. 31 | 32 | The *tracefs_snapshot_snap()* will allocate (if not already allocated) the snapshot 33 | buffer and then take a "snapshot" (swap the main buffer that's being written to with 34 | the allocated snapshot buffer). It will do this to the given _instance_ buffer or 35 | the top instance if _instance_ is NULL. 36 | 37 | The *tracefs_snapshot_clear()* will erase the content of the snapshot buffer for 38 | the given _instance_ or the top level instance if _instance_ is NULL. 39 | 40 | The *tracefs_snapshot_free()* will free the allocated snapshot for the given _instance_ 41 | or the top level instance if _instance_ is NULL. That is, if another call to 42 | *tracefs_snapshot_snap()* is done after this, then it will need to allocate 43 | the snapshot buffer again before it can take a snapshot. This function should 44 | be used to free up the kernel memory used by hte snapshot buffer when no longer in use. 45 | 46 | 47 | RETURN VALUE 48 | ------------ 49 | The *tracefs_snapshot_snap()*, *tracefs_snapshot_clear()* and the *tracefs_snapshot_free()* 50 | all return 0 on success and -1 on failure. 51 | 52 | EXAMPLE 53 | ------- 54 | [source,c] 55 | -- 56 | #include 57 | #include 58 | #include 59 | 60 | static int callback(struct tep_event *event, struct tep_record *record, int cpu, void *data) 61 | { 62 | static struct trace_seq seq; 63 | struct tep_handle *tep = event->tep; 64 | 65 | if (!seq.buffer) 66 | trace_seq_init(&seq); 67 | 68 | trace_seq_reset(&seq); 69 | 70 | tep_print_event(tep, &seq, record, "[%03d] %s-%d %6.1000d\t%s: %s\n", 71 | TEP_PRINT_CPU, 72 | TEP_PRINT_COMM, 73 | TEP_PRINT_PID, 74 | TEP_PRINT_TIME, 75 | TEP_PRINT_NAME, 76 | TEP_PRINT_INFO); 77 | trace_seq_do_printf(&seq); 78 | return 0; 79 | } 80 | 81 | int main (int argc, char **argv) 82 | { 83 | struct tracefs_instance *instance; 84 | struct tep_handle *tep; 85 | char *line = NULL; 86 | size_t len = 0; 87 | int ret; 88 | 89 | instance = tracefs_instance_create("my_snapshots"); 90 | if (!instance) { 91 | perror("creating instance"); 92 | exit(-1); 93 | } 94 | 95 | tep = tracefs_local_events(NULL); 96 | if (!tep) { 97 | perror("reading event formats"); 98 | goto out; 99 | } 100 | 101 | /* Make sure the snapshot buffer is allocated */ 102 | ret = tracefs_snapshot_snap(instance); 103 | if (ret < 0) 104 | goto out; 105 | 106 | ret = tracefs_event_enable(instance, "sched", NULL); 107 | if (ret < 0) { 108 | perror("enabling event"); 109 | goto out; 110 | } 111 | 112 | for (;;) { 113 | printf("Hit enter without text to take snapshot!\n"); 114 | printf("Enter any text to display the snapshot\n"); 115 | printf("Enter 'quit' to exit\n"); 116 | getline(&line, &len, stdin); 117 | ret = tracefs_snapshot_snap(instance); 118 | if (ret < 0) { 119 | perror("taking snapshot"); 120 | goto out; 121 | } 122 | if (!line) 123 | break; 124 | if (strlen(line) < 2) 125 | continue; 126 | if (strncmp(line, "quit", 4) == 0) 127 | break; 128 | tracefs_iterate_snapshot_events(tep, instance, NULL, 0, callback, NULL); 129 | } 130 | 131 | free(line); 132 | 133 | tracefs_instance_clear(instance); 134 | 135 | out: 136 | tracefs_snapshot_free(instance); 137 | tracefs_event_disable(instance, "sched", NULL); 138 | tracefs_instance_destroy(instance); 139 | tracefs_instance_free(instance); 140 | 141 | exit(0); 142 | } 143 | -- 144 | FILES 145 | ----- 146 | [verse] 147 | -- 148 | *tracefs.h* 149 | Header file to include in order to have access to the library APIs. 150 | *-ltracefs* 151 | Linker switch to add when building a program that uses the library. 152 | -- 153 | 154 | SEE ALSO 155 | -------- 156 | *tracefs_iterate_snapshot_events*(3) 157 | *libtracefs*(3), 158 | *libtraceevent*(3), 159 | *trace-cmd*(1) 160 | 161 | AUTHOR 162 | ------ 163 | [verse] 164 | -- 165 | *Steven Rostedt* 166 | -- 167 | REPORTING BUGS 168 | -------------- 169 | Report bugs to 170 | 171 | LICENSE 172 | ------- 173 | libtracefs is Free Software licensed under the GNU LGPL 2.1 174 | 175 | RESOURCES 176 | --------- 177 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 178 | 179 | COPYING 180 | ------- 181 | Copyright \(C) 2023 Google, LLC. Free use of this software is granted under 182 | the terms of the GNU Public License (GPL). 183 | -------------------------------------------------------------------------------- /Documentation/libtracefs-stream.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_trace_pipe_stream, tracefs_trace_pipe_print, tracefs_trace_pipe_stop - 7 | redirect the stream of trace data to an output or stdout. 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | ssize_t *tracefs_trace_pipe_stream*(int _fd_, struct tracefs_instance pass:[*]_instance_, int _flags_); 16 | ssize_t *tracefs_trace_pipe_print*(struct tracefs_instance pass:[*]_instance_, int _flags_); 17 | void *tracefs_trace_pipe_stop*(struct tracefs_instance pass:[*]_instance_); 18 | 19 | 20 | -- 21 | 22 | DESCRIPTION 23 | ----------- 24 | If NULL is passed as _instance_, the top trace instance is used. 25 | 26 | The reading of the trace_pipe file can be stopped by calling *tracefs_trace_pipe_stop()* 27 | which could be placed in a signal handler in case the application wants to stop the 28 | reading, for example, with the user pressing Ctrl-C. 29 | 30 | The *tracefs_trace_pipe_stream()* function redirects the stream of trace data to an output 31 | file. The "splice" system call is used to moves the data without copying between kernel 32 | address space and user address space. The _fd_ is the file descriptor of the output file 33 | and _flags_ is a bit mask of flags to be passed to the open system call of the trace_pipe 34 | file (see *open(2)*). If flags contain O_NONBLOCK, then that is also passed to the splice calls 35 | that may read the file to the output stream file descriptor. Note, O_RDONLY is or'd to 36 | the _flags_ and only O_NONBLOCK is useful for this parameter. 37 | 38 | The *tracefs_trace_pipe_print()* function is similar to *tracefs_trace_pipe_stream()*, but 39 | the stream of trace data is redirected to stdout. 40 | 41 | 42 | RETURN VALUE 43 | ------------ 44 | The *tracefs_trace_pipe_stream()*, and *tracefs_trace_pipe_print()* functions return the 45 | number of bytes transfered if the operation is successful, or -1 in case of an error. 46 | 47 | EXAMPLE 48 | ------- 49 | [source,c] 50 | -- 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #include 58 | 59 | void stop(int sig) 60 | { 61 | tracefs_trace_pipe_stop(NULL); 62 | } 63 | 64 | int main(int argc, char **argv) 65 | { 66 | mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 67 | const char *filename; 68 | int fd; 69 | int ret; 70 | 71 | if (argc < 2) { 72 | fprintf(stderr, "usage: %s output_file\n", argv[0]); 73 | exit(-1); 74 | } 75 | filename = argv[1]; 76 | fd = creat(filename, mode); 77 | if (fd < 0) { 78 | perror(filename); 79 | exit(-1); 80 | } 81 | signal(SIGINT, stop); 82 | ret = tracefs_trace_pipe_stream(fd, NULL, SPLICE_F_NONBLOCK); 83 | close(fd); 84 | 85 | return ret; 86 | } 87 | -- 88 | FILES 89 | ----- 90 | [verse] 91 | -- 92 | *tracefs.h* 93 | Header file to include in order to have access to the library APIs. 94 | *-ltracefs* 95 | Linker switch to add when building a program that uses the library. 96 | -- 97 | 98 | SEE ALSO 99 | -------- 100 | *libtracefs*(3), 101 | *libtraceevent*(3), 102 | *trace-cmd*(1), 103 | Documentation/trace/ftrace.rst from the Linux kernel tree 104 | 105 | AUTHOR 106 | ------ 107 | [verse] 108 | -- 109 | *Steven Rostedt* 110 | *Tzvetomir Stoyanov* 111 | -- 112 | REPORTING BUGS 113 | -------------- 114 | Report bugs to 115 | 116 | LICENSE 117 | ------- 118 | libtracefs is Free Software licensed under the GNU LGPL 2.1 119 | 120 | RESOURCES 121 | --------- 122 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 123 | 124 | COPYING 125 | ------- 126 | Copyright \(C) 2021 VMware, Inc. Free use of this software is granted under 127 | the terms of the GNU Public License (GPL). 128 | -------------------------------------------------------------------------------- /Documentation/libtracefs-traceon.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_trace_is_on, tracefs_trace_on, tracefs_trace_off, tracefs_trace_on_get_fd, 7 | tracefs_trace_on_fd, tracefs_trace_off_fd - Functions to enable or disable tracing. 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | int *tracefs_trace_is_on*(struct tracefs_instance pass:[*]_instance_); 16 | int *tracefs_trace_on*(struct tracefs_instance pass:[*]_instance_); 17 | int *tracefs_trace_off*(struct tracefs_instance pass:[*]_instance_); 18 | int *tracefs_trace_on_get_fd*(struct tracefs_instance pass:[*]_instance_); 19 | int *tracefs_trace_on_fd*(int _fd_); 20 | int *tracefs_trace_off_fd*(int _fd_); 21 | -- 22 | 23 | DESCRIPTION 24 | ----------- 25 | This set of functions can be used to check, enable or disable writing to the ring buffer in 26 | the given trace instance. The tracing is enabled when writing to the ring buffer is enabled. 27 | 28 | The *tracefs_trace_is_on()* function checks if tracing is enabled for the given _instance_. If 29 | _instance_ is NULL, the top instance is used. 30 | 31 | The *tracefs_trace_on()* and *tracefs_trace_off()* functions set the tracing in the _instance_ 32 | to enable or disable state. If _instance_ is NULL, the top instance is used. 33 | 34 | The *tracefs_trace_on_get_fd()* function returns a file descriptor to the "tracing_on" file from 35 | the given _instance_. If _instance_ is NULL, the top trace instance is used. The returned descriptor 36 | can be used for fast enabling or disabling the tracing of the instance. 37 | 38 | The *tracefs_trace_on_fd()* and *tracefs_trace_off_fd()* functions set the tracing state to enable 39 | or disable using the given _fd_. This file descriptor must be opened for writing with 40 | *tracefs_trace_on_get_fd*(3) of the desired trace instance. These functions are faster than 41 | *tracefs_trace_on* and *tracefs_trace_off*. 42 | 43 | RETURN VALUE 44 | ------------ 45 | The *tracefs_trace_is_on()* function returns 0 if tracing is disable, 1 if it is enabled or 46 | -1 in case of an error. 47 | 48 | The *tracefs_trace_on_get_fd()* function returns a file descriptor to "tracing_on" 49 | file for reading and writing, which must be closed wuth close(). In case of an error -1 is returned. 50 | 51 | The *tracefs_trace_on()*, *tracefs_trace_off()*, *tracefs_trace_on_fd()* and 52 | *tracefs_trace_off_fd()* functions return -1 in case of an error or 0 otherwise. 53 | 54 | EXAMPLE 55 | ------- 56 | [source,c] 57 | -- 58 | #include 59 | 60 | int ret; 61 | 62 | ret = tracefs_trace_is_on(NULL); 63 | if (ret == 0) { 64 | /* Tracing is disabled in the top instance */ 65 | } else if (ret == 1) { 66 | /* Tracing is enabled in the top instance */ 67 | } else { 68 | /* Error getting tracing state of the top instance */ 69 | } 70 | 71 | ... 72 | 73 | if (!tracefs_trace_on(NULL)) { 74 | /* Enabled tracing in the top instance */ 75 | 76 | ... 77 | 78 | if (!tracefs_trace_off(NULL)) { 79 | /* Disabled tracing in the top instance */ 80 | } else { 81 | /* Error disabling tracing in the top instance */ 82 | } 83 | } else { 84 | /* Error enabling tracing in the top instance */ 85 | } 86 | 87 | ... 88 | 89 | int fd = tracefs_trace_on_get_fd(NULL); 90 | 91 | if (fd < 0) { 92 | /* Error opening tracing_on file */ 93 | } 94 | ... 95 | if (!tracefs_trace_on_fd(fd)) { 96 | /* Enabled tracing in the top instance */ 97 | 98 | ... 99 | 100 | if (!tracefs_trace_off_fd(fd)) { 101 | /* Disabled tracing in the top instance */ 102 | } else { 103 | /* Error disabling tracing in the top instance */ 104 | } 105 | } else { 106 | /* Error enabling tracing in the top instance */ 107 | } 108 | 109 | ... 110 | 111 | close(fd); 112 | -- 113 | FILES 114 | ----- 115 | [verse] 116 | -- 117 | *tracefs.h* 118 | Header file to include in order to have access to the library APIs. 119 | *-ltracefs* 120 | Linker switch to add when building a program that uses the library. 121 | -- 122 | 123 | SEE ALSO 124 | -------- 125 | *libtracefs*(3), 126 | *libtraceevent*(3), 127 | *trace-cmd*(1) 128 | 129 | AUTHOR 130 | ------ 131 | [verse] 132 | -- 133 | *Steven Rostedt* 134 | *Tzvetomir Stoyanov* 135 | -- 136 | REPORTING BUGS 137 | -------------- 138 | Report bugs to 139 | 140 | LICENSE 141 | ------- 142 | libtracefs is Free Software licensed under the GNU LGPL 2.1 143 | 144 | RESOURCES 145 | --------- 146 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 147 | 148 | COPYING 149 | ------- 150 | Copyright \(C) 2021 VMware, Inc. Free use of this software is granted under 151 | the terms of the GNU Public License (GPL). 152 | -------------------------------------------------------------------------------- /Documentation/libtracefs-uprobes.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_uprobe_alloc,tracefs_uretprobe_alloc - Allocate new user (return) probe 7 | 8 | SYNOPSIS 9 | -------- 10 | [verse] 11 | -- 12 | *#include * 13 | 14 | struct tracefs_dynevent pass:[*] 15 | *tracefs_uprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, 16 | const char pass:[*]_file_, unsigned long long _offset_, const char pass:[*]_fetchargs_) 17 | struct tracefs_dynevent pass:[*] 18 | *tracefs_uretprobe_alloc*(const char pass:[*]_system_, const char pass:[*]_event_, 19 | const char pass:[*]_file_, unsigned long long _offset_, const char pass:[*]_fetchargs_) 20 | -- 21 | 22 | DESCRIPTION 23 | ----------- 24 | *tracefs_uprobe_alloc*() allocates a new uprobe context. It will be in the _system_ group 25 | (or uprobes if _system_ is NULL) and with _event_ name. The uprobe will be attached to _offset_ 26 | within the _file_. The list of arguments, described in _fetchargs_, will be fetched with the uprobe. 27 | The returned pointer to the user probe context must be freed with *tracefs_dynevent_free*(). 28 | The ubrobe is not configured in the system, tracefs_dynevent_* set of APIs can be used to configure 29 | it. 30 | 31 | The *tracefs_uretprobe_alloc*() behaves the same as *tracefs_uprobe_alloc*(), the only difference is 32 | that it allocates context to user return probe (uretprobe). 33 | 34 | RETURN VALUE 35 | ------------ 36 | The *tracefs_uprobe_alloc*() and *tracefs_uretprobe_alloc*() APIs return a pointer to an allocated 37 | tracefs_dynevent structure, describing the user probe. This pointer must be freed with 38 | *tracefs_dynevent_free*(3). Note, this only allocates a descriptor representing the uprobe. It does 39 | not modify the running system. On error NULL is returned. 40 | 41 | EXAMPLE 42 | ------- 43 | [source,c] 44 | -- 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | #include 51 | 52 | static int callback(struct tep_event *event, struct tep_record *record, 53 | int cpu, void *data) 54 | { 55 | struct trace_seq seq; 56 | 57 | trace_seq_init(&seq); 58 | tep_print_event(event->tep, &seq, record, "%d-%s: %s", 59 | TEP_PRINT_PID, TEP_PRINT_COMM, TEP_PRINT_NAME); 60 | trace_seq_puts(&seq, "'\n"); 61 | 62 | trace_seq_terminate(&seq); 63 | trace_seq_do_printf(&seq); 64 | trace_seq_destroy(&seq); 65 | 66 | return 0; 67 | } 68 | 69 | static pid_t run_exec(char **argv, char **env) 70 | { 71 | pid_t pid; 72 | 73 | pid = fork(); 74 | if (pid) 75 | return pid; 76 | 77 | execve(argv[0], argv, env); 78 | perror("exec"); 79 | exit(-1); 80 | } 81 | 82 | const char *myprobe = "my_urobes"; 83 | 84 | int main (int argc, char **argv, char **env) 85 | { 86 | struct tracefs_dynevent *uprobe, *uretprobe; 87 | struct tep_handle *tep; 88 | struct tracefs_instance *instance; 89 | const char *sysnames[] = { myprobe, NULL }; 90 | long addr; 91 | pid_t pid; 92 | 93 | if (argc < 3) { 94 | printf("usage: %s file_offset command\n", argv[0]); 95 | exit(-1); 96 | } 97 | addr = strtol(argv[1], NULL, 0); 98 | 99 | instance = tracefs_instance_create("exec_open"); 100 | if (!instance) { 101 | perror("creating instance"); 102 | exit(-1); 103 | } 104 | 105 | tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_UPROBE|TRACEFS_DYNEVENT_URETPROBE, true); 106 | 107 | uprobe = tracefs_uprobe_alloc(myprobe, "user_probe", argv[2], addr, NULL); 108 | uretprobe = tracefs_uretprobe_alloc(myprobe, "user_retprobe", argv[2], addr, NULL); 109 | if (!uprobe || !uretprobe) { 110 | perror("allocating user probes"); 111 | exit(-1); 112 | } 113 | 114 | if (tracefs_dynevent_create(uprobe) || 115 | tracefs_dynevent_create(uretprobe)) { 116 | perror("creating user probes"); 117 | exit(-1); 118 | } 119 | 120 | tep = tracefs_local_events_system(NULL, sysnames); 121 | if (!tep) { 122 | perror("reading events"); 123 | exit(-1); 124 | } 125 | 126 | tracefs_event_enable(instance, myprobe, "user_probe"); 127 | tracefs_event_enable(instance, myprobe, "user_retprobe"); 128 | 129 | pid = run_exec(&argv[2], env); 130 | 131 | /* Let the child start to run */ 132 | sched_yield(); 133 | 134 | do { 135 | tracefs_load_cmdlines(NULL, tep); 136 | tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, NULL); 137 | } while (waitpid(pid, NULL, WNOHANG) != pid); 138 | 139 | /* disable and destroy the events */ 140 | tracefs_dynevent_destroy(uprobe, true); 141 | tracefs_dynevent_destroy(uretprobe, true); 142 | tracefs_dynevent_free(uprobe); 143 | tracefs_dynevent_free(uretprobe); 144 | tracefs_instance_destroy(instance); 145 | 146 | return 0; 147 | } 148 | -- 149 | 150 | FILES 151 | ----- 152 | [verse] 153 | -- 154 | *tracefs.h* 155 | Header file to include in order to have access to the library APIs. 156 | *-ltracefs* 157 | Linker switch to add when building a program that uses the library. 158 | -- 159 | 160 | SEE ALSO 161 | -------- 162 | *libtracefs*(3), 163 | *libtraceevent*(3), 164 | *trace-cmd*(1) 165 | 166 | AUTHOR 167 | ------ 168 | [verse] 169 | -- 170 | *Steven Rostedt* 171 | *Tzvetomir Stoyanov* 172 | -- 173 | 174 | REPORTING BUGS 175 | -------------- 176 | Report bugs to 177 | 178 | LICENSE 179 | ------- 180 | libtracefs is Free Software licensed under the GNU LGPL 2.1 181 | 182 | RESOURCES 183 | --------- 184 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 185 | 186 | COPYING 187 | ------- 188 | Copyright \(C) 2022 VMware, Inc. Free use of this software is granted under 189 | the terms of the GNU Public License (GPL). 190 | -------------------------------------------------------------------------------- /Documentation/libtracefs-utils.txt: -------------------------------------------------------------------------------- 1 | libtracefs(3) 2 | ============= 3 | 4 | NAME 5 | ---- 6 | tracefs_tracers, tracefs_tracer_available, tracefs_get_clock, tracefs_list_free, 7 | tracefs_list_add, tracefs_list_size - Helper functions for working with trace file system. 8 | 9 | SYNOPSIS 10 | -------- 11 | [verse] 12 | -- 13 | *#include * 14 | 15 | char pass:[*]pass:[*]*tracefs_tracers*(const char pass:[*]_tracing_dir_); 16 | bool *tracefs_tracer_available*(const char pass:[*]_tracing_dir_, const char pass:[*]_tracer_); 17 | char pass:[*]*tracefs_get_clock*(struct tracefs_instance pass:[*]_instance_); 18 | void *tracefs_list_free*(char pass:[*]pass:[*]_list_); 19 | char pass:[**]*tracefs_list_add*(char **_list_, const char *_string_); 20 | int *tracefs_list_size*(char pass:[**]_list_); 21 | -- 22 | 23 | DESCRIPTION 24 | ----------- 25 | Various useful functions for working with trace file system. 26 | 27 | The *tracefs_tracers()* function returns array of strings with the 28 | names of supported tracer plugins, located in the given _tracing_dir_ 29 | directory. This could be NULL or the location of the tracefs mount point 30 | for the trace systems of the local machine, or it may be a path to a copy 31 | of the tracefs directory from another machine. The last entry in the array 32 | as a NULL pointer. The array must be freed with *tracefs_list_free()* API. 33 | 34 | The *tracefs_tracer_available()* returns true if the _tracer_ is available 35 | in the given _tracing_dir_director_, and false otherwise. 36 | 37 | The *tracefs_get_clock()* function returns name of the current trace clock, 38 | used in the given _instance_. If _instance_ is NULL, the clock of the main 39 | trace instance is returned. The returned string must be freed with free(). 40 | 41 | The *tracefs_list_free()* function frees an array of strings, returned by 42 | *tracefs_event_systems()*, *tracefs_system_events()* and *tracefs_tracers()* 43 | APIs. 44 | 45 | The *tracefs_list_add()* function adds _string_ to the string _list_. If 46 | _list_ is NULL, then a new list is created with the first element a copy 47 | of _string_, and the second element will be a NULL pointer. If _list_ is 48 | not NULL, then it is reallocated to include a new element and a NULL terminator, 49 | and the new allocated array is returned. The list passed in should be ignored, 50 | as it wil be freed if a new one was allocated. 51 | 52 | The *tracefs_list_size()* is a fast way to find out the number of elements 53 | in a string array that is to be freed with *tracefs_list_free()*. Note, this 54 | depends on meta data that is created for these lists and will not work on 55 | normal string arrays like argv. 56 | 57 | RETURN VALUE 58 | ------------ 59 | The *tracefs_tracers()* returns array of strings. The last element in that 60 | array is a NULL pointer. The array must be freed with *tracefs_list_free()* API. 61 | In case of an error, NULL is returned. 62 | 63 | The *tracefs_tracer_available()* returns true if the _tracer_ is available, 64 | and false otherwise. 65 | 66 | The *tracefs_get_clock()* returns string, that must be freed with free(), or NULL 67 | in case of an error. 68 | 69 | The *tracefs_list_add()* returns an allocated string array that must be freed 70 | with *tracefs_list_free()* on success or NULL on error. If NULL is returned, 71 | then the passed in _list_ is untouched. Thus, *tracefs_list_add()* should be 72 | treated similarly to *realloc*(3). 73 | 74 | The *tracefs_list_size()* returns the number of strings in the _list_. The 75 | passed in list must be one that is to be freed with *tracefs_list_free()* 76 | as the list has meta data that is used to determine the size and this does 77 | not work on any normal string array like argv. 78 | 79 | EXAMPLE 80 | ------- 81 | [source,c] 82 | -- 83 | #include 84 | 85 | char **tracers = tracefs_tracers(NULL); 86 | 87 | if (tracers) { 88 | /* Got tracer plugins from the top trace instance */ 89 | ... 90 | tracefs_list_free(tracers); 91 | } 92 | .... 93 | char *clock = tracefs_get_clock(NULL); 94 | 95 | if (clock) { 96 | /* Got current trace clock of the top trace instance */ 97 | ... 98 | free(clock); 99 | } 100 | -- 101 | FILES 102 | ----- 103 | [verse] 104 | -- 105 | *tracefs.h* 106 | Header file to include in order to have access to the library APIs. 107 | *-ltracefs* 108 | Linker switch to add when building a program that uses the library. 109 | -- 110 | 111 | SEE ALSO 112 | -------- 113 | *libtracefs*(3), 114 | *libtraceevent*(3), 115 | *trace-cmd*(1) 116 | 117 | AUTHOR 118 | ------ 119 | [verse] 120 | -- 121 | *Steven Rostedt* 122 | *Tzvetomir Stoyanov* 123 | -- 124 | REPORTING BUGS 125 | -------------- 126 | Report bugs to 127 | 128 | LICENSE 129 | ------- 130 | libtracefs is Free Software licensed under the GNU LGPL 2.1 131 | 132 | RESOURCES 133 | --------- 134 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 135 | 136 | COPYING 137 | ------- 138 | Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under 139 | the terms of the GNU Public License (GPL). 140 | -------------------------------------------------------------------------------- /Documentation/manpage-1.72.xsl: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Documentation/manpage-base.xsl: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 18 | 19 | 20 | 21 | sp 22 | 23 | 24 | 25 | 26 | 30 | 31 | 32 | br 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Documentation/manpage-bold-literal.xsl: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 9 | 10 | 11 | fB 12 | 13 | 14 | fR 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Documentation/manpage-normal.xsl: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | 8 | 9 | 10 | \ 11 | . 12 | 13 | 14 | -------------------------------------------------------------------------------- /Documentation/manpage-suppress-sp.xsl: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Documentation/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1 2 | # 3 | # Copyright (c) 2023 Daniel Wagner, SUSE LLC 4 | 5 | # input text file: man page section 6 | 7 | sources = { 8 | 'libtracefs-sqlhist.txt.1': '1', 9 | 'libtracefs-cpu-buf.txt': '3', 10 | 'libtracefs-cpu-map.txt': '3', 11 | 'libtracefs-cpu-open.txt': '3', 12 | 'libtracefs-cpu.txt': '3', 13 | 'libtracefs-dynevents.txt': '3', 14 | 'libtracefs-eprobes.txt': '3', 15 | 'libtracefs-error.txt': '3', 16 | 'libtracefs-events-file.txt': '3', 17 | 'libtracefs-events-tep.txt': '3', 18 | 'libtracefs-events.txt': '3', 19 | 'libtracefs-files.txt': '3', 20 | 'libtracefs-filter-pid.txt': '3', 21 | 'libtracefs-filter.txt': '3', 22 | 'libtracefs-function-filter.txt': '3', 23 | 'libtracefs-guest.txt': '3', 24 | 'libtracefs-hist-cont.txt': '3', 25 | 'libtracefs-hist-mod.txt': '3', 26 | 'libtracefs-hist.txt': '3', 27 | 'libtracefs-instances-affinity.txt': '3', 28 | 'libtracefs-instances-file-manip.txt': '3', 29 | 'libtracefs-instances-files.txt': '3', 30 | 'libtracefs-instances-manage.txt': '3', 31 | 'libtracefs-instances-stat.txt': '3', 32 | 'libtracefs-instances-subbuf.txt': '3', 33 | 'libtracefs-instances-utils.txt': '3', 34 | 'libtracefs-iterator.txt': '3', 35 | 'libtracefs-kprobes.txt': '3', 36 | 'libtracefs-log.txt': '3', 37 | 'libtracefs-marker_raw.txt': '3', 38 | 'libtracefs-marker.txt': '3', 39 | 'libtracefs-option-get.txt': '3', 40 | 'libtracefs-option-misc.txt': '3', 41 | 'libtracefs-options.txt': '3', 42 | 'libtracefs-snapshot.txt': '3', 43 | 'libtracefs-sql.txt': '3', 44 | 'libtracefs-stream.txt': '3', 45 | 'libtracefs-synth2.txt': '3', 46 | 'libtracefs-synth-info.txt': '3', 47 | 'libtracefs-synth.txt': '3', 48 | 'libtracefs-traceon.txt': '3', 49 | 'libtracefs-tracer.txt': '3', 50 | 'libtracefs.txt': '3', 51 | 'libtracefs-uprobes.txt': '3', 52 | 'libtracefs-utils.txt': '3', 53 | } 54 | 55 | conf_dir = meson.current_source_dir() + '/' 56 | top_source_dir = meson.current_source_dir() + '/../' 57 | 58 | ## 59 | # For asciidoc ... 60 | # -7.1.2, no extra settings are needed. 61 | # 8.0-, set ASCIIDOC8. 62 | # 63 | 64 | # 65 | # For docbook-xsl ... 66 | # -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0) 67 | # 1.69.0, no extra settings are needed? 68 | # 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP? 69 | # 1.71.1, no extra settings are needed? 70 | # 1.72.0, set DOCBOOK_XSL_172. 71 | # 1.73.0-, set ASCIIDOC_NO_ROFF 72 | # 73 | 74 | # 75 | # If you had been using DOCBOOK_XSL_172 in an attempt to get rid 76 | # of 'the ".ft C" problem' in your generated manpages, and you 77 | # instead ended up with weird characters around callouts, try 78 | # using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8). 79 | # 80 | 81 | if get_option('asciidoctor') 82 | asciidoc = find_program('asciidoctor') 83 | asciidoc_extra = ['-a', 'compat-mode'] 84 | asciidoc_extra += ['-I.'] 85 | asciidoc_extra += ['-r', 'asciidoctor-extensions'] 86 | asciidoc_extra += ['-a', 'mansource=libtraceevent'] 87 | asciidoc_extra += ['-a', 'manmanual="libtraceevent Manual"'] 88 | asciidoc_html = 'xhtml5' 89 | else 90 | asciidoc = find_program('asciidoc') 91 | asciidoc_extra = ['--unsafe'] 92 | asciidoc_extra += ['-f', conf_dir + 'asciidoc.conf'] 93 | asciidoc_html = 'xhtml11' 94 | 95 | r = run_command(asciidoc, '--version', check: true) 96 | v = r.stdout().strip() 97 | if v.version_compare('>=8.0') 98 | asciidoc_extra += ['-a', 'asciidoc7compatible'] 99 | endif 100 | endif 101 | 102 | manpage_xsl = conf_dir + 'manpage-normal.xsl' 103 | 104 | if get_option('docbook-xls-172') 105 | asciidoc_extra += ['-a', 'libtraceevent-asciidoc-no-roff'] 106 | manpage_xsl = conf_dir + 'manpage-1.72.xsl' 107 | elif get_option('asciidoc-no-roff') 108 | # docbook-xsl after 1.72 needs the regular XSL, but will not 109 | # pass-thru raw roff codes from asciidoc.conf, so turn them off. 110 | asciidoc_extra += ['-a', 'libtraceevent-asciidoc-no-roff'] 111 | endif 112 | 113 | xmlto = find_program('xmlto') 114 | xmlto_extra = [] 115 | 116 | if get_option('man-bold-literal') 117 | xmlto_extra += ['-m ', conf_dir + 'manpage-bold-literal.xsl'] 118 | endif 119 | 120 | if get_option('docbook-suppress-sp') 121 | xmlto_extra += ['-m ', conf_dir + 'manpage-suppress-sp.xsl'] 122 | endif 123 | 124 | check_doc = custom_target( 125 | 'check-doc', 126 | output: 'dummy', 127 | command : [ 128 | top_source_dir + 'check-manpages.sh', 129 | meson.current_source_dir()]) 130 | 131 | gen = generator( 132 | asciidoc, 133 | output: '@BASENAME@.xml', 134 | arguments: [ 135 | '-b', 'docbook', 136 | '-d', 'manpage', 137 | '-a', 'libtraceevent_version=' + meson.project_version(), 138 | '-o', '@OUTPUT@'] 139 | + asciidoc_extra 140 | + ['@INPUT@']) 141 | 142 | man = [] 143 | html = [] 144 | foreach txt, section : sources 145 | # build man page(s) 146 | xml = gen.process(txt) 147 | man += custom_target( 148 | txt.underscorify() + '_man', 149 | input: xml, 150 | output: '@BASENAME@.' + section, 151 | depends: check_doc, 152 | command: [ 153 | xmlto, 154 | '-m', manpage_xsl, 155 | 'man', 156 | '-o', '@OUTPUT@'] 157 | + xmlto_extra 158 | + ['@INPUT@']) 159 | 160 | # build html pages 161 | html += custom_target( 162 | txt.underscorify() + '_html', 163 | input: txt, 164 | output: '@BASENAME@.html', 165 | depends: check_doc, 166 | command: [ 167 | asciidoc, 168 | '-b', asciidoc_html, 169 | '-d', 'manpage', 170 | '-a', 'libtraceevent_version=' + meson.project_version(), 171 | '-o', '@OUTPUT@'] 172 | + asciidoc_extra 173 | + ['@INPUT@']) 174 | endforeach 175 | 176 | # Install path workaround because: 177 | # 178 | # - xmlto might generate more than one file and we would to tell meson 179 | # about those output files. We could figure out which files are generated 180 | # (see sed match in check-manpages.sh). 181 | # 182 | # - The man page generation puts all the generated files under sub dirs 183 | # and it's not obvious how to tell Meson it should not do this without 184 | # causing the install step to fail (confusion where the generated files 185 | # are stored) 186 | # 187 | # - The documentation build is not part of the 'build' target. The user 188 | # has explicitly to trigger the doc build. Hence the documentation is 189 | # not added to the 'install' target. 190 | # 191 | # Thus just use a plain old shell script to move the generated files to the 192 | # right location. 193 | 194 | conf = configuration_data() 195 | conf.set('SRCDIR', meson.current_build_dir()) 196 | conf.set('MANDIR', mandir) 197 | conf.set('HTMLDIR', htmldir) 198 | configure_file( 199 | input: 'install-docs.sh.in', 200 | output: 'install-docs.sh', 201 | configuration: conf) 202 | 203 | meson.add_install_script( 204 | join_paths(meson.current_build_dir(), 'install-docs.sh')) 205 | -------------------------------------------------------------------------------- /Makefile.meson: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | undefine CFLAGS 4 | 5 | # Makefiles suck: This macro sets a default value of $(2) for the 6 | # variable named by $(1), unless the variable has been set by 7 | # environment or command line. This is necessary for CC and AR 8 | # because make sets default values, so the simpler ?= approach 9 | # won't work as expected. 10 | define allow-override 11 | $(if $(or $(findstring environment,$(origin $(1))),\ 12 | $(findstring command line,$(origin $(1)))),,\ 13 | $(eval $(1) = $(2))) 14 | endef 15 | 16 | $(call allow-override,MESON,meson) 17 | $(call allow-override,MESON_BUILD_DIR,build) 18 | 19 | 20 | all: compile 21 | 22 | PHONY += compile 23 | compile: $(MESON_BUILD_DIR) force 24 | $(MESON) compile -C $(MESON_BUILD_DIR) 25 | 26 | $(MESON_BUILD_DIR): 27 | $(MESON) setup --prefix=$(prefix) $(MESON_BUILD_DIR) 28 | 29 | install: compile 30 | $(MESON) install -C $(MESON_BUILD_DIR) 31 | 32 | docs: $(MESON_BUILD_DIR) 33 | $(MESON) compile -C build docs 34 | 35 | PHONY += clean_meson 36 | clean_meson: 37 | $(Q)$(RM) -rf $(MESON_BUILD_DIR) 38 | 39 | PHONY += force 40 | force: 41 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | The official repository is here: 3 | 4 | https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 5 | 6 | This repository requires libtraceevent to be installed: 7 | 8 | https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ 9 | 10 | 11 | To build: 12 | 13 | make; 14 | sudo make install; 15 | 16 | To build in a specific directory outside of the source directory: 17 | 18 | make O=/path/to/build; sudo make O=/path/to/build 19 | 20 | Note that the path needs to exist before building. 21 | 22 | To set the install path (the expected final location): 23 | 24 | make prefix=/usr; sudo make O=/path/to/build 25 | 26 | To install in a directory not for the local system (for use to move 27 | to another machine): 28 | 29 | make DESTDIR=/path/to/dest/ install 30 | 31 | Note, if you have write permission to the DESTDIR, then there is 32 | no reason to use sudo or switch to root. 33 | 34 | Note, DESTDIR must end with '/', otherwise the files will be appended 35 | to the path, which will most likely have unwanted results. 36 | 37 | Contributions: 38 | 39 | For questions about the use of the library, please send email to: 40 | 41 | linux-trace-users@vger.kernel.org 42 | 43 | Subscribe: http://vger.kernel.org/vger-lists.html#linux-trace-users 44 | Archives: https://lore.kernel.org/linux-trace-users/ 45 | 46 | For contributions to development, please send patches to: 47 | 48 | linux-trace-devel@vger.kernel.org 49 | 50 | Subscribe: http://vger.kernel.org/vger-lists.html#linux-trace-devel 51 | Archives: https://lore.kernel.org/linux-trace-devel/ 52 | 53 | Note, this project follows the style of submitting patches as described 54 | by the Linux kernel. 55 | 56 | https://www.kernel.org/doc/html/v5.4/process/submitting-patches.html 57 | -------------------------------------------------------------------------------- /check-manpages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: LGPL-2.1 3 | # Copyright (C) 2022, Google Inc, Steven Rostedt 4 | # 5 | # This checks if any function is listed in a man page that is not listed 6 | # in the main man page. 7 | 8 | if [ $# -lt 1 ]; then 9 | echo "usage: check-manpages man-page-path" 10 | exit 1 11 | fi 12 | 13 | cd $1 14 | 15 | MAIN=libtracefs 16 | MAIN_FILE=${MAIN}.txt 17 | 18 | PROCESSED="" 19 | 20 | # Ignore man pages that do not contain functions 21 | IGNORE="libtracefs-options.txt" 22 | 23 | for man in ${MAIN}-*.txt; do 24 | 25 | for a in `sed -ne '/^NAME/,/^SYNOP/{/^[a-z]/{s/, *$//;s/,/\n/g;s/ //g;s/-.*$/-/;/-/{s/-//p;q};p}}' $man`; do 26 | if [ "${PROCESSED/:${a} /}" != "${PROCESSED}" ]; then 27 | P="${PROCESSED/:${a} */}" 28 | echo "Found ${a} in ${man} and in ${P/* /}" 29 | fi 30 | PROCESSED="${man}:${a} ${PROCESSED}" 31 | if [ "${IGNORE/$man/}" != "${IGNORE}" ]; then 32 | continue 33 | fi 34 | if ! grep -q '\*'${a}'\*' $MAIN_FILE; then 35 | if [ "$last" == "" ]; then 36 | echo 37 | fi 38 | if [ "$last" != "$man" ]; then 39 | echo "Missing functions from $MAIN_FILE that are in $man" 40 | last=$man 41 | fi 42 | echo " ${a}" 43 | fi 44 | done 45 | done 46 | 47 | DEPRECATED="*tracefs_event_append_filter* *tracefs_event_verify_filter*" 48 | 49 | sed -ne 's/^[a-z].*[ \*]\([a-z_][a-z_]*\)(.*/\1/p' -e 's/^\([a-z_][a-z_]*\)(.*/\1/p' ../include/tracefs.h | while read f; do 50 | if ! grep -q '\*'${f}'\*' $MAIN_FILE; then 51 | if [ "${DEPRECATED/\*$f\*/}" != "${DEPRECATED}" ]; then 52 | continue; 53 | fi 54 | if [ "$last" == "" ]; then 55 | echo 56 | echo "Missing functions from $MAIN_FILE that are in tracefs.h" 57 | last=$f 58 | fi 59 | echo " ${f}" 60 | fi 61 | done 62 | -------------------------------------------------------------------------------- /include/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1 2 | # 3 | # Copyright (c) 2023 Daniel Wagner, SUSE LLC 4 | 5 | headers = [ 6 | 'tracefs.h', 7 | ] 8 | 9 | foreach h : headers 10 | install_headers(h, subdir : 'libtracefs') 11 | endforeach 12 | -------------------------------------------------------------------------------- /include/tracefs-local.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1 */ 2 | /* 3 | * Copyright (C) 2019, VMware, Tzvetomir Stoyanov 4 | * 5 | */ 6 | #ifndef _TRACE_FS_LOCAL_H 7 | #define _TRACE_FS_LOCAL_H 8 | 9 | #include 10 | #include 11 | 12 | #define __hidden __attribute__((visibility ("hidden"))) 13 | #define __weak __attribute__((weak)) 14 | 15 | #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) 16 | 17 | /* Will cause a division by zero warning if cond is true */ 18 | #define BUILD_BUG_ON(cond) \ 19 | do { if (!(1/!(cond))) { } } while (0) 20 | 21 | #define HASH_BITS 10 22 | 23 | struct tracefs_options_mask { 24 | unsigned long long mask; 25 | }; 26 | 27 | struct follow_event { 28 | struct tep_event *event; 29 | void *callback_data; 30 | int (*callback)(struct tep_event *, 31 | struct tep_record *, 32 | int, void *); 33 | }; 34 | 35 | struct tracefs_instance { 36 | struct tracefs_options_mask supported_opts; 37 | struct tracefs_options_mask enabled_opts; 38 | struct follow_event *followers; 39 | struct follow_event *missed_followers; 40 | char *trace_dir; 41 | char *name; 42 | pthread_mutex_t lock; 43 | int ref; 44 | int flags; 45 | int ftrace_filter_fd; 46 | int ftrace_notrace_fd; 47 | int ftrace_marker_fd; 48 | int ftrace_marker_raw_fd; 49 | int nr_followers; 50 | int nr_missed_followers; 51 | bool pipe_keep_going; 52 | bool iterate_keep_going; 53 | }; 54 | 55 | struct tracefs_buffer_stat { 56 | ssize_t entries; 57 | ssize_t overrun; 58 | ssize_t commit_overrun; 59 | ssize_t bytes; 60 | long long oldest_ts; 61 | long long now_ts; 62 | ssize_t dropped_events; 63 | ssize_t read_events; 64 | }; 65 | 66 | extern const struct tep_format_field tfs_common_stacktrace; 67 | 68 | extern pthread_mutex_t tfs_toplevel_lock; 69 | 70 | static inline pthread_mutex_t *trace_get_lock(struct tracefs_instance *instance) 71 | { 72 | return instance ? &instance->lock : &tfs_toplevel_lock; 73 | } 74 | 75 | void tfs_put_instance(struct tracefs_instance *instance); 76 | int tfs_get_instance(struct tracefs_instance *instance); 77 | 78 | /* Can be overridden */ 79 | void tracefs_warning(const char *fmt, ...); 80 | 81 | char *tfs_strstrip(char *str); 82 | int tfs_str_read_file(const char *file, char **buffer, bool warn); 83 | char *tfs_append_file(const char *dir, const char *name); 84 | char *tfs_find_tracing_dir(bool debugfs); 85 | 86 | #ifndef ACCESSPERMS 87 | #define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) /* 0777 */ 88 | #endif 89 | 90 | #ifndef ALLPERMS 91 | #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) /* 07777 */ 92 | #endif 93 | 94 | #ifndef DEFFILEMODE 95 | #define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /* 0666*/ 96 | #endif 97 | 98 | struct tracefs_options_mask * 99 | tfs_supported_opts_mask(struct tracefs_instance *instance); 100 | 101 | struct tracefs_options_mask * 102 | tfs_enabled_opts_mask(struct tracefs_instance *instance); 103 | 104 | char **tfs_list_create_empty(void); 105 | int tfs_list_pop(char **list); 106 | 107 | char *tfs_append_string(char *str, const char *delim, const char *add); 108 | int tfs_test_state(int state); 109 | bool tfs_verify_event_field(struct tep_event *event, 110 | const char *field_name, 111 | const struct tep_format_field **ptr_field); 112 | int tfs_append_filter(char **filter, unsigned int *state, 113 | unsigned int *open_parens, 114 | struct tep_event *event, 115 | enum tracefs_filter type, 116 | const char *field_name, 117 | enum tracefs_compare compare, 118 | const char *val); 119 | 120 | void *tfs_mmap(int fd, struct kbuffer *kbuf); 121 | void tfs_unmap(void *mapping); 122 | int tfs_mmap_load_subbuf(void *mapping, struct kbuffer *kbuf); 123 | int tfs_mmap_read(void *mapping, void *buffer); 124 | 125 | struct tracefs_synth * 126 | tfs_synth_init_from(struct tep_handle *tep, 127 | const char *start_system, 128 | const char *start_event); 129 | 130 | #define HIST_COUNTER_TYPE (TRACEFS_HIST_KEY_MAX + 100) 131 | int tfs_synth_add_start_field(struct tracefs_synth *synth, 132 | const char *start_field, 133 | const char *name, 134 | enum tracefs_hist_key_type type, 135 | int cnt); 136 | 137 | /* Internal interface for ftrace dynamic events */ 138 | 139 | struct tracefs_dynevent { 140 | char *trace_file; 141 | char *prefix; 142 | char *system; 143 | char *event; 144 | char *address; 145 | char *format; 146 | enum tracefs_dynevent_type type; 147 | }; 148 | 149 | struct tracefs_dynevent * 150 | tfs_dynevent_alloc(enum tracefs_dynevent_type type, const char *system, 151 | const char *event, const char *address, const char *format); 152 | int tfs_dynevent_get_count(unsigned int types, const char *system); 153 | 154 | int tfs_load_events(struct tep_handle *tep, 155 | const char *tracing_dir, 156 | const char *system); 157 | int tfs_rescan_events(struct tep_handle *tep, 158 | const char *tracing_dir, 159 | const char *system); 160 | struct tep_event * 161 | tfs_get_tep_event(struct tep_handle *tep, 162 | const char *system, 163 | const char *name); 164 | 165 | unsigned int tfs_quick_hash(const char *str); 166 | 167 | #endif /* _TRACE_FS_LOCAL_H */ 168 | -------------------------------------------------------------------------------- /libtracefs.pc.template: -------------------------------------------------------------------------------- 1 | prefix=INSTALL_PREFIX 2 | libdir=${prefix}/LIB_DIR 3 | includedir=${prefix}/HEADER_DIR 4 | 5 | Name: libtracefs 6 | URL: https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ 7 | Description: Library for accessing ftrace file system 8 | Version: LIB_VERSION 9 | Requires: libtraceevent > LIBTRACEEVENT_MIN 10 | Cflags: -I${includedir} 11 | Libs: -L${libdir} -ltracefs 12 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1 2 | # 3 | # Copyright (c) 2023 Daniel Wagner, SUSE LLC 4 | 5 | project( 6 | 'libtracefs', ['c'], 7 | meson_version: '>= 0.50.0', 8 | license: 'LGPL-2.1', 9 | version: '1.8.2', 10 | default_options: [ 11 | 'c_std=gnu99', 12 | 'buildtype=debug', 13 | 'default_library=both', 14 | 'prefix=/usr/local', 15 | 'warning_level=1']) 16 | 17 | library_version = meson.project_version() 18 | 19 | libtraceevent_dep = dependency('libtraceevent', version: '>= 1.8.1', required: true) 20 | threads_dep = dependency('threads', required: true) 21 | cunit_dep = dependency('cunit', required : false) 22 | 23 | prefixdir = get_option('prefix') 24 | datadir = join_paths(prefixdir, get_option('datadir')) 25 | bindir = join_paths(prefixdir, get_option('bindir')) 26 | mandir = join_paths(prefixdir, get_option('mandir')) 27 | htmldir = join_paths(prefixdir, get_option('htmldir')) 28 | 29 | add_project_arguments( 30 | [ 31 | '-D_GNU_SOURCE', 32 | ], 33 | language : 'c') 34 | 35 | incdir = include_directories(['include']) 36 | 37 | subdir('src') 38 | subdir('include') 39 | if get_option('utest') and cunit_dep.found() 40 | subdir('utest') 41 | endif 42 | if get_option('samples') 43 | subdir('samples') 44 | endif 45 | 46 | if get_option('doc') 47 | subdir('Documentation') 48 | 49 | custom_target( 50 | 'docs', 51 | output: 'docs', 52 | depends: [html, man], 53 | command: ['echo']) 54 | endif 55 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1 2 | # 3 | # Copyright (c) 2023 Daniel Wagner, SUSE LLC 4 | 5 | option('htmldir', type : 'string', value : 'share/doc/libtracefs-doc', 6 | description : 'directory for HTML documentation') 7 | option('asciidoctor', type : 'boolean', value: false, 8 | description : 'use asciidoctor instead of asciidoc') 9 | option('docbook-xls-172', type : 'boolean', value : false, 10 | description : 'enable docbook XLS 172 workaround') 11 | option('asciidoc-no-roff', type : 'boolean', value : false, 12 | description : 'enable no roff workaround') 13 | option('man-bold-literal', type : 'boolean', value : false, 14 | description : 'enable bold literals') 15 | option('docbook-suppress-sp', type : 'boolean', value : false, 16 | description : 'docbook suppress sp') 17 | option('doc', type : 'boolean', value: true, 18 | description : 'produce documentation') 19 | option('samples', type : 'boolean', value: true, 20 | description : 'build samples') 21 | option('utest', type : 'boolean', value: true, 22 | description : 'build utest') 23 | -------------------------------------------------------------------------------- /samples/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1 2 | 3 | # 4 | # The samples are pulled out of the examples used in the man pages 5 | # that are located in the Documentation directory. 6 | # 7 | 8 | include $(src)/scripts/utils.mk 9 | 10 | EXAMPLES := 11 | EXAMPLES += dynevents 12 | EXAMPLES += kprobes 13 | EXAMPLES += eprobes 14 | EXAMPLES += uprobes 15 | EXAMPLES += synth 16 | EXAMPLES += error 17 | EXAMPLES += filter 18 | EXAMPLES += function-filter 19 | EXAMPLES += hist 20 | EXAMPLES += hist-cont 21 | EXAMPLES += tracer 22 | EXAMPLES += stream 23 | EXAMPLES += instances-affinity 24 | EXAMPLES += cpu 25 | EXAMPLES += guest 26 | EXAMPLES += cpu-buf 27 | EXAMPLES += instances-stat 28 | EXAMPLES += instances-subbuf 29 | EXAMPLES += cpu-map 30 | 31 | TARGETS := 32 | TARGETS += sqlhist 33 | TARGETS += $(EXAMPLES) 34 | 35 | sdir := $(obj)/bin 36 | 37 | TARGETS := $(patsubst %,$(sdir)/%,$(TARGETS)) 38 | 39 | all: $(TARGETS) 40 | 41 | $(bdir)/sqlhist.c: $(src)/Documentation/libtracefs-sql.txt 42 | $(call extract_example,$<,$@) 43 | 44 | $(bdir)/%.c: ../Documentation/libtracefs-%.txt 45 | $(call extract_example,$<,$@) 46 | 47 | $(sdir): 48 | @mkdir -p $(sdir) 49 | 50 | sqlhist: $(sdir)/sqlhist 51 | 52 | $(TARGETS): $(sdir) 53 | 54 | # sqlhist is unique and stands on its own 55 | $(sdir)/sqlhist: $(bdir)/sqlhist.c $(LIBTRACEFS_STATIC) 56 | $(call do_sample_build,$@,$<) 57 | 58 | $(sdir)/%: $(bdir)/%.o 59 | $(call do_sample_build,$@,$<) 60 | 61 | $(EXAMPLES): $(patsubst %,$(sdir)/%,$(TARGETS)) 62 | 63 | ## The intermediate files get removed by Make. 64 | ## To examine the .c files created by one of the man pages, 65 | ## uncomment the below, and replace the XX with the exec example 66 | ## name, and the file will not be discarded by make. 67 | # 68 | # $(bdir)/XX.o: $(bdir)/XX.c 69 | # $(CC) -g -Wall $(CFLAGS) -c -o $@ $^ -I../include/ $(LIBTRACEEVENT_INCLUDES) 70 | $(bdir)/cpu-map.o: $(bdir)/cpu-map.c 71 | $(CC) -g -Wall $(CFLAGS) -c -o $@ $^ -I../include/ $(LIBTRACEEVENT_INCLUDES) 72 | $(bdir)/kprobes.o: $(bdir)/kprobes.c 73 | $(CC) -g -Wall $(CFLAGS) -c -o $@ $^ -I../include/ $(LIBTRACEEVENT_INCLUDES) 74 | 75 | $(bdir)/%.o: $(bdir)/%.c 76 | $(call do_sample_obj,$@,$^) 77 | 78 | $(bdir)/XX.o: $(bdir)/hist.c 79 | $(CC) -g -Wall $(CFLAGS) -c -o $@ $^ -I../include/ $(LIBTRACEEVENT_INCLUDES) 80 | 81 | clean: 82 | $(Q)$(call do_clean,$(sdir)/* $(bdir)/sqlhist.c $(bdir)/sqlhist.o) 83 | 84 | .PHONY: sqlhist 85 | -------------------------------------------------------------------------------- /samples/cpu-map.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static void read_subbuf(struct tep_handle *tep, struct kbuffer *kbuf) 6 | { 7 | static struct trace_seq seq; 8 | struct tep_record record; 9 | int missed_events; 10 | 11 | if (seq.buffer) 12 | trace_seq_reset(&seq); 13 | else 14 | trace_seq_init(&seq); 15 | 16 | while ((record.data = kbuffer_read_event(kbuf, &record.ts))) { 17 | record.size = kbuffer_event_size(kbuf); 18 | missed_events = kbuffer_missed_events(kbuf); 19 | if (missed_events) { 20 | printf("[MISSED EVENTS"); 21 | if (missed_events > 0) 22 | printf(": %d]\n", missed_events); 23 | else 24 | printf("]\n"); 25 | } 26 | kbuffer_next_event(kbuf, NULL); 27 | tep_print_event(tep, &seq, &record, 28 | "%s-%d %6.1000d\t%s: %s\n", 29 | TEP_PRINT_COMM, 30 | TEP_PRINT_PID, 31 | TEP_PRINT_TIME, 32 | TEP_PRINT_NAME, 33 | TEP_PRINT_INFO); 34 | trace_seq_do_printf(&seq); 35 | trace_seq_reset(&seq); 36 | } 37 | } 38 | 39 | int main (int argc, char **argv) 40 | { 41 | struct tracefs_cpu *tcpu; 42 | struct tep_handle *tep; 43 | struct kbuffer *kbuf; 44 | bool mapped; 45 | int cpu; 46 | 47 | if (argc < 2 || !isdigit(argv[1][0])) { 48 | printf("usage: %s cpu\n\n", argv[0]); 49 | exit(-1); 50 | } 51 | 52 | cpu = atoi(argv[1]); 53 | 54 | tep = tracefs_local_events(NULL); 55 | if (!tep) { 56 | perror("Reading trace event formats"); 57 | exit(-1); 58 | } 59 | 60 | tcpu = tracefs_cpu_open_mapped(NULL, cpu, 0); 61 | if (!tcpu) { 62 | perror("Open CPU 0 file"); 63 | exit(-1); 64 | } 65 | 66 | /* 67 | * If this kernel supports mapping, use normal read, 68 | * otherwise use the piped buffer read, although if 69 | * the mapping succeeded, tracefs_cpu_buffered_read_buf() 70 | * acts the same as tracefs_cpu_read_buf(). But this is just 71 | * an example on how to use tracefs_cpu_is_mapped(). 72 | */ 73 | mapped = tracefs_cpu_is_mapped(tcpu); 74 | if (!mapped) 75 | printf("Was not able to map, falling back to buffered read\n"); 76 | while ((kbuf = mapped ? tracefs_cpu_read_buf(tcpu, true) : 77 | tracefs_cpu_buffered_read_buf(tcpu, true))) { 78 | read_subbuf(tep, kbuf); 79 | } 80 | 81 | kbuf = tracefs_cpu_flush_buf(tcpu); 82 | if (kbuf) 83 | read_subbuf(tep, kbuf); 84 | 85 | tracefs_cpu_close(tcpu); 86 | tep_free(tep); 87 | 88 | return 0; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /samples/extract-example.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat $1 | sed -ne '/^EXAMPLE/,/FILES/ { /EXAMPLE/,+2d ; /^FILES/d ; /^--/d ; p}' > $2 4 | -------------------------------------------------------------------------------- /samples/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1 2 | # 3 | # Copyright (c) 2023 Daniel Wagner, SUSE LLC 4 | 5 | examples = [ 6 | 'dynevents', 7 | 'kprobes', 8 | 'eprobes', 9 | 'uprobes', 10 | 'synth', 11 | 'error', 12 | 'filter', 13 | 'function-filter', 14 | 'hist', 15 | 'hist-cont', 16 | 'tracer', 17 | 'stream', 18 | 'instances-affinity', 19 | 'cpu', 20 | ] 21 | 22 | extract_examples = find_program('extract-example.sh') 23 | gen = generator( 24 | extract_examples, 25 | output: '@BASENAME@.c', 26 | arguments: ['@INPUT@', '@OUTPUT@']) 27 | 28 | foreach ex : examples 29 | src = gen.process(meson.current_source_dir() + '/../Documentation/libtracefs-@0@.txt'.format(ex)) 30 | executable( 31 | ex.underscorify(), 32 | src, 33 | dependencies: [libtracefs_dep, libtraceevent_dep, threads_dep], 34 | include_directories: [incdir]) 35 | endforeach 36 | 37 | # sqlhist is unique and stands on its own 38 | src = gen.process(meson.current_source_dir() + '/../Documentation/libtracefs-sql.txt') 39 | executable( 40 | 'sqlhist', 41 | src, 42 | dependencies: [libtracefs_dep, libtraceevent_dep, threads_dep], 43 | include_directories: [incdir], 44 | install: true, 45 | install_dir: bindir) 46 | -------------------------------------------------------------------------------- /samples/sqlhist.bash: -------------------------------------------------------------------------------- 1 | # sqlhist completion 2 | 3 | # use the library tracefs_sql() completion 4 | 5 | thisdir=`dirname $BASH_SOURCE` 6 | if [ -e $thisdir/tracefs_sql.bash ]; then 7 | . $thisdir/tracefs_sql.bash 8 | elif [ -e $thisdir/../src/tracefs_sql.bash ]; then 9 | . $thisdir/../src/tracefs_sql.bash 10 | else 11 | tracefs_sql_completion() 12 | { 13 | return 14 | } 15 | fi 16 | 17 | found_select() 18 | { 19 | local words=("$@") 20 | local i=$COMP_CWORD 21 | 22 | while [ $i -gt 0 ]; do 23 | let i=$i-1 24 | local w=$(echo ${words[$i]} | tr A-Z a-z) 25 | if [ $w == "select" ]; then 26 | return 0 27 | fi 28 | done 29 | return 1 30 | } 31 | 32 | _sqlhist_complete() 33 | { 34 | local cur="" 35 | local prev="" 36 | local words=() 37 | 38 | # Not to use COMP_WORDS to avoid buggy behavior of Bash when 39 | # handling with words including ":", like: 40 | # 41 | # prev="${COMP_WORDS[COMP_CWORD-1]}" 42 | # cur="${COMP_WORDS[COMP_CWORD]}" 43 | # 44 | # Instead, we use _get_comp_words_by_ref() magic. 45 | _get_comp_words_by_ref -n : cur prev words 46 | 47 | if `found_select ${words[@]}` ; then 48 | tracefs_sql_completion "$prev" "$cur" ${words[@]} 49 | return 50 | fi 51 | local cmds=$(sqlhist -h 2>&1 | \ 52 | grep '^ *-' | sed -e 's/^ *\(-[^ ]*\).*/\1/') 53 | COMPREPLY=( $(compgen -W "${cmds} SELECT" -- "${cur}") ) 54 | if [ ${#COMPREPLY[@]} -eq 0 ]; then 55 | local w="select" 56 | if [ "$w" != "${w##$cur}" ]; then 57 | COMPREPLY=("$w") 58 | fi 59 | fi 60 | } 61 | complete -F _sqlhist_complete sqlhist 62 | -------------------------------------------------------------------------------- /scripts/features.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | 3 | # taken from perf which was based on Linux Kbuild 4 | # try-cc 5 | # Usage: option = $(call try-cc, source-to-build, cc-options) 6 | try-cc = $(shell sh -c \ 7 | 'TMP="$(BUILD_OUTPUT)$(TMPOUT).$$$$"; \ 8 | echo "$(1)" | \ 9 | $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \ 10 | rm -f "$$TMP"') 11 | 12 | define SOURCE_PTRACE 13 | #include 14 | #include 15 | 16 | int main (void) 17 | { 18 | int ret; 19 | ret = ptrace(PTRACE_ATTACH, 0, NULL, 0); 20 | ptrace(PTRACE_TRACEME, 0, NULL, 0); 21 | ptrace(PTRACE_GETSIGINFO, 0, NULL, NULL); 22 | ptrace(PTRACE_GETEVENTMSG, 0, NULL, NULL); 23 | ptrace(PTRACE_SETOPTIONS, NULL, NULL, 24 | PTRACE_O_TRACEFORK | 25 | PTRACE_O_TRACEVFORK | 26 | PTRACE_O_TRACECLONE | 27 | PTRACE_O_TRACEEXIT); 28 | ptrace(PTRACE_CONT, NULL, NULL, 0); 29 | ptrace(PTRACE_DETACH, 0, NULL, NULL); 30 | ptrace(PTRACE_SETOPTIONS, 0, NULL, 31 | PTRACE_O_TRACEFORK | 32 | PTRACE_O_TRACEVFORK | 33 | PTRACE_O_TRACECLONE | 34 | PTRACE_O_TRACEEXIT); 35 | return ret; 36 | } 37 | endef 38 | -------------------------------------------------------------------------------- /scripts/utils.mk: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1 2 | 3 | # Utils 4 | 5 | PWD := $(shell /bin/pwd) 6 | GOBJ = $(notdir $(strip $@)) 7 | BASE1 = $(notdir $(strip $1)) 8 | BASE2 = $(notdir $(strip $2)) 9 | BASEPWD = $(notdir $(strip $(PWD))) 10 | 11 | 12 | ifeq ($(VERBOSE),1) 13 | Q = 14 | S = 15 | else 16 | Q = @ 17 | S = -s 18 | endif 19 | 20 | # Use empty print_* macros if either SILENT or VERBOSE. 21 | ifeq ($(findstring 1,$(SILENT)$(VERBOSE)),1) 22 | print_compile = 23 | print_app_build = 24 | print_fpic_compile = 25 | print_shared_lib_compile = 26 | print_plugin_obj_compile = 27 | print_plugin_build = 28 | print_install = 29 | print_uninstall = 30 | print_update = 31 | print_descend = 32 | print_clean = 33 | print_extract = 34 | print_sample_build = 35 | print_sample_obj = 36 | else 37 | print_compile = echo ' COMPILE '$(GOBJ); 38 | print_app_build = echo ' BUILD '$(GOBJ); 39 | print_fpic_compile = echo ' COMPILE FPIC '$(GOBJ); 40 | print_shared_lib_compile = echo ' COMPILE SHARED LIB '$(GOBJ); 41 | print_plugin_obj_compile = echo ' COMPILE PLUGIN OBJ '$(GOBJ); 42 | print_plugin_build = echo ' BUILD PLUGIN '$(GOBJ); 43 | print_static_lib_build = echo ' BUILD STATIC LIB '$(GOBJ); 44 | print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; 45 | print_uninstall = echo ' UNINSTALL $(DESTDIR_SQ)$1'; 46 | print_update = echo ' UPDATE '$(GOBJ); 47 | print_descend = echo ' DESCEND '$(BASE1) $(BASE2); 48 | print_clean = echo ' CLEAN '$(BASEPWD); 49 | print_extract = echo ' EXTRACT '$(GOBJ); 50 | print_sample_build = echo ' COMPILE SAMPLE '$(GOBJ); 51 | print_sample_obj = echo ' COMPILE SAMPLE OBJ '$(GOBJ); 52 | endif 53 | 54 | do_fpic_compile = \ 55 | ($(print_fpic_compile) \ 56 | $(CC) -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ -MP -c $(CPPFLAGS) $(CFLAGS) $(EXT) -fPIC $< -o $@) 57 | 58 | do_compile = \ 59 | ($(if $(GENERATE_PIC), $(do_fpic_compile), \ 60 | $(print_compile) \ 61 | $(CC) -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ -MP -c $(CPPFLAGS) $(CFLAGS) $(EXT) $< -o $@)) 62 | 63 | do_app_build = \ 64 | ($(print_app_build) \ 65 | $(CC) $^ -rdynamic -o $@ $(LDFLAGS) $(CONFIG_LIBS) $(LIBS)) 66 | 67 | do_build_static_lib = \ 68 | ($(print_static_lib_build) \ 69 | if [ -f $@ ]; then \ 70 | mv $@ $@.rm; $(RM) $@.rm; \ 71 | fi; \ 72 | $(AR) rcs $@ $^) 73 | 74 | do_compile_shared_library = \ 75 | ($(print_shared_lib_compile) \ 76 | $(CC) --shared $^ '-Wl,-soname,$(1),-rpath=$$ORIGIN' -o $@ $(LDFLAGS) $(LIBS)) 77 | 78 | do_compile_plugin_obj = \ 79 | ($(print_plugin_obj_compile) \ 80 | $(CC) -c $(CPPFLAGS) $(CFLAGS) -fPIC -o $@ $<) 81 | 82 | do_plugin_build = \ 83 | ($(print_plugin_build) \ 84 | $(CC) $(CFLAGS) $(LDFLAGS) -shared -nostartfiles -o $@ $<) 85 | 86 | do_compile_python_plugin_obj = \ 87 | ($(print_plugin_obj_compile) \ 88 | $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PYTHON_DIR_SQ) $(PYTHON_INCLUDES) -fPIC -o $@ $<) 89 | 90 | do_python_plugin_build = \ 91 | ($(print_plugin_build) \ 92 | $(CC) $< -shared $(LDFLAGS) $(PYTHON_LDFLAGS) -o $@) 93 | 94 | do_clean = \ 95 | ($(print_clean) \ 96 | $(RM) $1) 97 | 98 | extract_example = \ 99 | $(Q)($(print_extract) \ 100 | cat $1 | sed -ne '/^EXAMPLE/,/FILES/ { /EXAMPLE/,+2d ; /^FILES/d ; /^--/d ; p}' > $2) 101 | 102 | do_sample_build = \ 103 | $(Q)($(print_sample_build) \ 104 | $(CC) -o $1 $2 $(CFLAGS) $(LIBTRACEFS_STATIC) $(LIBTRACEEVENT_LIBS) -lpthread) 105 | 106 | do_sample_obj = \ 107 | $(Q)($(print_sample_obj) \ 108 | $(CC) -g -Wall -c $(CFLAGS) -o $1 $2 -I../include/ $(LIBTRACEEVENT_INCLUDES)) 109 | 110 | ifneq ($(findstring $(MAKEFLAGS), w),w) 111 | PRINT_DIR = --no-print-directory 112 | else 113 | NO_SUBDIR = : 114 | endif 115 | 116 | # 117 | # Define a callable command for descending to a new directory 118 | # 119 | # Call by doing: $(call descend,directory[,target]) 120 | # 121 | descend = \ 122 | ($(print_descend) \ 123 | mkdir -p $(obj)/$(BASE1); \ 124 | $(MAKE) $(PRINT_DIR) bdir=$(obj)/$(BASE1) -C $(1) $(2)) 125 | 126 | descend_clean = \ 127 | $(MAKE) $(PRINT_DIR) bdir=$(obj)/$(BASE1) -C $(1) clean 128 | 129 | define make_version.h 130 | (echo '/* This file is automatically generated. Do not modify. */'; \ 131 | echo \#define VERSION_CODE $(shell \ 132 | expr $(VERSION) \* 256 + $(PATCHLEVEL)); \ 133 | echo '#define EXTRAVERSION ' $(EXTRAVERSION); \ 134 | echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \ 135 | echo '#define FILE_VERSION '$(FILE_VERSION); \ 136 | if [ -d $(src)/.git ]; then \ 137 | d=`git diff`; \ 138 | x=""; \ 139 | if [ ! -z "$$d" ]; then x="+"; fi; \ 140 | echo '#define VERSION_GIT "'$(shell \ 141 | git log -1 --pretty=format:"%H" 2>/dev/null)$$x'"'; \ 142 | else \ 143 | echo '#define VERSION_GIT "not-a-git-repo"'; \ 144 | fi \ 145 | ) > $1 146 | endef 147 | 148 | define update_version.h 149 | ($(call make_version.h, $@.tmp); \ 150 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ 151 | rm -f $@.tmp; \ 152 | else \ 153 | $(print_update) \ 154 | mv -f $@.tmp $@; \ 155 | fi); 156 | endef 157 | 158 | define update_dir 159 | (echo $1 > $@.tmp; \ 160 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ 161 | rm -f $@.tmp; \ 162 | else \ 163 | $(print_update) \ 164 | mv -f $@.tmp $@; \ 165 | fi); 166 | endef 167 | 168 | define build_prefix 169 | (echo $1 > $@.tmp; \ 170 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ 171 | rm -f $@.tmp; \ 172 | else \ 173 | $(print_update) \ 174 | mv -f $@.tmp $@; \ 175 | fi); 176 | endef 177 | 178 | define do_install_mkdir 179 | if [ ! -d '$(DESTDIR_SQ)$1' ]; then \ 180 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \ 181 | fi 182 | endef 183 | 184 | define do_install 185 | $(print_install) \ 186 | $(call do_install_mkdir,$2); \ 187 | $(INSTALL) $(if $3,-m $3,) $1 '$(DESTDIR_SQ)$2' 188 | endef 189 | 190 | define do_install_data 191 | $(print_install) \ 192 | if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ 193 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ 194 | fi; \ 195 | $(INSTALL) -m 644 $1 '$(DESTDIR_SQ)$2' 196 | endef 197 | 198 | define do_install_pkgconfig_file 199 | if [ -n "${pkgconfig_dir}" ]; then \ 200 | $(call do_install,$(PKG_CONFIG_FILE),$(pkgconfig_dir),644); \ 201 | else \ 202 | (echo Failed to locate pkg-config directory) 1>&2; \ 203 | fi 204 | endef 205 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1 2 | 3 | include $(src)/scripts/utils.mk 4 | 5 | OBJS = 6 | OBJS += tracefs-utils.o 7 | OBJS += tracefs-instance.o 8 | OBJS += tracefs-events.o 9 | OBJS += tracefs-tools.o 10 | OBJS += tracefs-marker.o 11 | OBJS += tracefs-kprobes.o 12 | OBJS += tracefs-hist.o 13 | OBJS += tracefs-stats.o 14 | OBJS += tracefs-filter.o 15 | OBJS += tracefs-dynevents.o 16 | OBJS += tracefs-eprobes.o 17 | OBJS += tracefs-uprobes.o 18 | OBJS += tracefs-record.o 19 | OBJS += tracefs-mmap.o 20 | ifeq ($(VSOCK_DEFINED), 1) 21 | OBJS += tracefs-vsock.o 22 | endif 23 | ifeq ($(PERF_DEFINED), 1) 24 | OBJS += tracefs-perf.o 25 | endif 26 | 27 | # Order matters for the the three below 28 | OBJS += sqlhist-lex.o 29 | OBJS += sqlhist.tab.o 30 | OBJS += tracefs-sqlhist.o 31 | 32 | OBJS := $(OBJS:%.o=$(bdir)/%.o) 33 | 34 | $(LIBTRACEFS_STATIC): $(OBJS) 35 | $(Q)$(call do_build_static_lib) 36 | 37 | $(LIBTRACEFS_SHARED): $(OBJS) 38 | $(Q)$(call do_compile_shared_library,$(notdir $(LIBTRACEFS_SHARED_VERSION))) 39 | 40 | $(LIBTRACEFS_SHARED_VERSION): $(LIBTRACEFS_SHARED) 41 | @ln -sf $( 5 | #include 6 | 7 | #include 8 | 9 | struct str_hash; 10 | 11 | struct sql_table; 12 | 13 | struct sqlhist_bison { 14 | void *scanner; 15 | const char *buffer; 16 | size_t buffer_size; 17 | size_t buffer_idx; 18 | int line_no; 19 | int line_idx; 20 | struct sql_table *table; 21 | char *parse_error_str; 22 | struct str_hash *str_hash[1 << HASH_BITS]; 23 | }; 24 | 25 | #include "sqlhist.tab.h" 26 | 27 | enum filter_type { 28 | FILTER_GROUP, 29 | FILTER_NOT_GROUP, 30 | FILTER_EQ, 31 | FILTER_NE, 32 | FILTER_LE, 33 | FILTER_LT, 34 | FILTER_GE, 35 | FILTER_GT, 36 | FILTER_BIN_AND, 37 | FILTER_STR_CMP, 38 | FILTER_AND, 39 | FILTER_OR, 40 | }; 41 | 42 | enum compare_type { 43 | COMPARE_GROUP, 44 | COMPARE_ADD, 45 | COMPARE_SUB, 46 | COMPARE_MUL, 47 | COMPARE_DIV, 48 | COMPARE_BIN_AND, 49 | COMPARE_BIN_OR, 50 | COMPARE_AND, 51 | COMPARE_OR, 52 | }; 53 | 54 | char *tfs_store_str(struct sqlhist_bison *sb, const char *str); 55 | 56 | int tfs_table_start(struct sqlhist_bison *sb); 57 | 58 | void *tfs_add_field(struct sqlhist_bison *sb, const char *field, const char *label); 59 | 60 | void *tfs_add_filter(struct sqlhist_bison *sb, void *A, void *B, enum filter_type op); 61 | 62 | int tfs_add_match(struct sqlhist_bison *sb, void *A, void *B); 63 | void *tfs_add_compare(struct sqlhist_bison *sb, void *A, void *B, enum compare_type type); 64 | int tfs_add_where(struct sqlhist_bison *sb, void *expr); 65 | 66 | int tfs_add_selection(struct sqlhist_bison *sb, void *item, const char *label); 67 | int tfs_add_from(struct sqlhist_bison *sb, void *item); 68 | int tfs_add_to(struct sqlhist_bison *sb, void *item); 69 | void *tfs_add_cast(struct sqlhist_bison *sb, void *field, const char *type); 70 | void *tfs_add_cast_buckets(struct sqlhist_bison *sb, void *field, const char *type, int num); 71 | 72 | void *tfs_add_string(struct sqlhist_bison *sb, const char *str); 73 | void *tfs_add_number(struct sqlhist_bison *sb, long val); 74 | 75 | extern void tfs_sql_parse_error(struct sqlhist_bison *sb, const char *text, 76 | const char *fmt, va_list ap); 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/sqlhist.l: -------------------------------------------------------------------------------- 1 | %{ 2 | /* code here */ 3 | 4 | /* If you change this file, run: make sqlhist_remake */ 5 | 6 | #include 7 | #include "sqlhist-parse.h" 8 | 9 | extern int tfs_my_yyinput(void *extra, char *buf, int max); 10 | 11 | #undef YY_INPUT 12 | #define YY_INPUT(b, r, m) ({r = tfs_my_yyinput(yyextra, b, m);}) 13 | 14 | #define YY_NO_INPUT 15 | #define YY_NO_UNPUT 16 | 17 | #define YY_EXTRA_TYPE struct sqlhist_bison * 18 | 19 | #define yytext yyg->yytext_r 20 | 21 | #define TRACE_SB ((struct sqlhist_bison *)yyextra) 22 | #define HANDLE_COLUMN do { TRACE_SB->line_idx += strlen(yytext); } while (0) 23 | 24 | %} 25 | 26 | %option caseless 27 | %option reentrant 28 | %option bison-bridge 29 | 30 | field \\?[a-z_][a-z0-9_\.]* 31 | qstring \"[^\"]*\" 32 | 33 | hexnum 0x[0-9a-f]+ 34 | number [0-9a-f]+ 35 | %% 36 | 37 | select { HANDLE_COLUMN; return SELECT; } 38 | as { HANDLE_COLUMN; return AS; } 39 | from { HANDLE_COLUMN; return FROM; } 40 | join { HANDLE_COLUMN; return JOIN; } 41 | on { HANDLE_COLUMN; return ON; } 42 | where { HANDLE_COLUMN; return WHERE; } 43 | cast { HANDLE_COLUMN; return CAST; } 44 | 45 | sym-offset { 46 | HANDLE_COLUMN; 47 | yylval->string = tfs_store_str(TRACE_SB, yyg->yytext_r); 48 | return FIELD; 49 | } 50 | 51 | {qstring} { 52 | HANDLE_COLUMN; 53 | yylval->string = tfs_store_str(TRACE_SB, yyg->yytext_r); 54 | return STRING; 55 | } 56 | 57 | {field} { 58 | const char *str = yyg->yytext_r; 59 | HANDLE_COLUMN; 60 | if (str[0] == '\\') { str++; }; 61 | yylval->string = tfs_store_str(TRACE_SB, str); 62 | return FIELD; 63 | } 64 | 65 | {hexnum} { 66 | HANDLE_COLUMN; 67 | yylval->number = strtol(yyg->yytext_r, NULL, 0); 68 | return NUMBER; 69 | } 70 | 71 | {number} { 72 | HANDLE_COLUMN; 73 | yylval->number = strtol(yyg->yytext_r, NULL, 0); 74 | return NUMBER; 75 | } 76 | 77 | \!= { HANDLE_COLUMN; return NEQ; } 78 | \<= { HANDLE_COLUMN; return LE; } 79 | \>= { HANDLE_COLUMN; return GE; } 80 | == { HANDLE_COLUMN; return EQ; } 81 | && { HANDLE_COLUMN; return AND; } 82 | "||" { HANDLE_COLUMN; return OR; } 83 | [<>&~] { HANDLE_COLUMN; return yytext[0]; } 84 | 85 | [\!()\-\+\*/,=] { HANDLE_COLUMN; return yytext[0]; } 86 | 87 | [ \t] { HANDLE_COLUMN; } 88 | \n { TRACE_SB->line_idx = 0; TRACE_SB->line_no++; } 89 | 90 | . { HANDLE_COLUMN; return PARSE_ERROR; } 91 | %% 92 | 93 | int yywrap(void *data) 94 | { 95 | return 1; 96 | } 97 | 98 | void yyerror(struct sqlhist_bison *sb, char *fmt, ...) 99 | { 100 | struct yyguts_t * yyg = (struct yyguts_t*)sb->scanner; 101 | va_list ap; 102 | 103 | va_start(ap, fmt); 104 | tfs_sql_parse_error(sb, yytext, fmt, ap); 105 | va_end(ap); 106 | } 107 | -------------------------------------------------------------------------------- /src/sqlhist.tab.h: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 3.8.2. */ 2 | 3 | /* Bison interface for Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, 6 | Inc. 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . */ 20 | 21 | /* As a special exception, you may create a larger work that contains 22 | part or all of the Bison parser skeleton and distribute that work 23 | under terms of your choice, so long as that work isn't itself a 24 | parser generator using the skeleton or a modified version thereof 25 | as a parser skeleton. Alternatively, if you modify or redistribute 26 | the parser skeleton itself, you may (at your option) remove this 27 | special exception, which will cause the skeleton and the resulting 28 | Bison output files to be licensed under the GNU General Public 29 | License without this special exception. 30 | 31 | This special exception was added by the Free Software Foundation in 32 | version 2.2 of Bison. */ 33 | 34 | /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, 35 | especially those whose name start with YY_ or yy_. They are 36 | private implementation details that can be changed or removed. */ 37 | 38 | #ifndef YY_TRACEFS_SQLHIST_TAB_H_INCLUDED 39 | # define YY_TRACEFS_SQLHIST_TAB_H_INCLUDED 40 | /* Debug traces. */ 41 | #ifndef TRACEFS_DEBUG 42 | # if defined YYDEBUG 43 | #if YYDEBUG 44 | # define TRACEFS_DEBUG 1 45 | # else 46 | # define TRACEFS_DEBUG 0 47 | # endif 48 | # else /* ! defined YYDEBUG */ 49 | # define TRACEFS_DEBUG 1 50 | # endif /* ! defined YYDEBUG */ 51 | #endif /* ! defined TRACEFS_DEBUG */ 52 | #if TRACEFS_DEBUG 53 | extern int tracefs_debug; 54 | #endif 55 | 56 | /* Token kinds. */ 57 | #ifndef TRACEFS_TOKENTYPE 58 | # define TRACEFS_TOKENTYPE 59 | enum tracefs_tokentype 60 | { 61 | TRACEFS_EMPTY = -2, 62 | TRACEFS_EOF = 0, /* "end of file" */ 63 | TRACEFS_error = 256, /* error */ 64 | TRACEFS_UNDEF = 257, /* "invalid token" */ 65 | AS = 258, /* AS */ 66 | SELECT = 259, /* SELECT */ 67 | FROM = 260, /* FROM */ 68 | JOIN = 261, /* JOIN */ 69 | ON = 262, /* ON */ 70 | WHERE = 263, /* WHERE */ 71 | PARSE_ERROR = 264, /* PARSE_ERROR */ 72 | CAST = 265, /* CAST */ 73 | NUMBER = 266, /* NUMBER */ 74 | field_type = 267, /* field_type */ 75 | STRING = 268, /* STRING */ 76 | FIELD = 269, /* FIELD */ 77 | LE = 270, /* LE */ 78 | GE = 271, /* GE */ 79 | EQ = 272, /* EQ */ 80 | NEQ = 273, /* NEQ */ 81 | AND = 274, /* AND */ 82 | OR = 275 /* OR */ 83 | }; 84 | typedef enum tracefs_tokentype tracefs_token_kind_t; 85 | #endif 86 | 87 | /* Value type. */ 88 | #if ! defined TRACEFS_STYPE && ! defined TRACEFS_STYPE_IS_DECLARED 89 | union TRACEFS_STYPE 90 | { 91 | #line 47 "sqlhist.y" 92 | 93 | int s32; 94 | char *string; 95 | long number; 96 | void *expr; 97 | 98 | #line 99 "sqlhist.tab.h" 99 | 100 | }; 101 | typedef union TRACEFS_STYPE TRACEFS_STYPE; 102 | # define TRACEFS_STYPE_IS_TRIVIAL 1 103 | # define TRACEFS_STYPE_IS_DECLARED 1 104 | #endif 105 | 106 | 107 | 108 | 109 | int tracefs_parse (struct sqlhist_bison *sb); 110 | 111 | /* "%code provides" blocks. */ 112 | #line 38 "sqlhist.y" 113 | 114 | #define YYSTYPE TRACEFS_STYPE 115 | #define yylex tracefs_lex 116 | #define yyerror tracefs_error 117 | 118 | #line 119 "sqlhist.tab.h" 119 | 120 | #endif /* !YY_TRACEFS_SQLHIST_TAB_H_INCLUDED */ 121 | -------------------------------------------------------------------------------- /src/sqlhist.y: -------------------------------------------------------------------------------- 1 | %{ 2 | /* If you change this file, run: make sqlhist_remake */ 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "sqlhist-parse.h" 9 | 10 | #define scanner sb->scanner 11 | 12 | extern int yylex(YYSTYPE *yylval, void *); 13 | extern void yyerror(struct sqlhist_bison *, char *fmt, ...); 14 | 15 | #define CHECK_RETURN_PTR(x) \ 16 | do { \ 17 | if (!(x)) { \ 18 | printf("FAILED MEMORY: %s\n", #x); \ 19 | return -ENOMEM; \ 20 | } \ 21 | } while (0) 22 | 23 | #define CHECK_RETURN_VAL(x) \ 24 | do { \ 25 | if ((x) < 0) { \ 26 | printf("FAILED MEMORY: %s\n", #x); \ 27 | return -ENOMEM; \ 28 | } \ 29 | } while (0) 30 | 31 | %} 32 | 33 | %define api.pure 34 | 35 | /* Change the globals to use tracefs_ prefix */ 36 | %define api.prefix{tracefs_} 37 | %code provides 38 | { 39 | #define YYSTYPE TRACEFS_STYPE 40 | #define yylex tracefs_lex 41 | #define yyerror tracefs_error 42 | } 43 | 44 | %lex-param {void *scanner} 45 | %parse-param {struct sqlhist_bison *sb} 46 | 47 | %union { 48 | int s32; 49 | char *string; 50 | long number; 51 | void *expr; 52 | } 53 | 54 | %token AS SELECT FROM JOIN ON WHERE PARSE_ERROR CAST 55 | %token NUMBER field_type 56 | %token STRING 57 | %token FIELD 58 | %token LE GE EQ NEQ AND OR 59 | 60 | %left '+' '-' 61 | %left '*' '/' 62 | %left '<' '>' 63 | %left AND OR 64 | 65 | %type name label 66 | 67 | %type selection_expr field item named_field 68 | %type selection_addition 69 | %type compare compare_list compare_cmds compare_items 70 | %type compare_and_or 71 | %type str_val val 72 | 73 | %% 74 | 75 | start : 76 | select_statement 77 | ; 78 | 79 | label : AS name { CHECK_RETURN_PTR($$ = tfs_store_str(sb, $2)); } 80 | | name { CHECK_RETURN_PTR($$ = tfs_store_str(sb, $1)); } 81 | ; 82 | 83 | select : SELECT { tfs_table_start(sb); } 84 | ; 85 | 86 | select_statement : 87 | select selection_list table_exp 88 | ; 89 | 90 | selection_list : 91 | selection 92 | | selection ',' selection_list 93 | ; 94 | 95 | selection : 96 | selection_expr 97 | { 98 | CHECK_RETURN_VAL(tfs_add_selection(sb, $1, NULL)); 99 | } 100 | | selection_expr label 101 | { 102 | CHECK_RETURN_VAL(tfs_add_selection(sb, $1, $2)); 103 | } 104 | ; 105 | 106 | selection_expr : 107 | field 108 | | '(' field ')' { $$ = $2; } 109 | | selection_addition 110 | | '(' selection_addition ')' { $$ = $2; } 111 | | CAST '(' field AS FIELD '=' NUMBER ')' { 112 | $$ = tfs_add_cast_buckets(sb, $3, $5, $7); 113 | CHECK_RETURN_PTR($$); 114 | } 115 | | CAST '(' field AS FIELD ')' { 116 | $$ = tfs_add_cast(sb, $3, $5); 117 | CHECK_RETURN_PTR($$); 118 | } 119 | ; 120 | 121 | selection_addition : 122 | field '+' field 123 | { 124 | $$ = tfs_add_compare(sb, $1, $3, COMPARE_ADD); 125 | CHECK_RETURN_PTR($$); 126 | } 127 | | field '-' field 128 | { 129 | $$ = tfs_add_compare(sb, $1, $3, COMPARE_SUB); 130 | CHECK_RETURN_PTR($$); 131 | } 132 | ; 133 | 134 | item : 135 | named_field 136 | | field 137 | ; 138 | 139 | field : 140 | FIELD { $$ = tfs_add_field(sb, $1, NULL); CHECK_RETURN_PTR($$); } 141 | ; 142 | 143 | named_field : 144 | FIELD label { $$ = tfs_add_field(sb, $1, $2); CHECK_RETURN_PTR($$); } 145 | ; 146 | 147 | name : 148 | FIELD 149 | ; 150 | 151 | str_val : 152 | STRING { $$ = tfs_add_string(sb, $1); CHECK_RETURN_PTR($$); } 153 | ; 154 | 155 | val : 156 | str_val 157 | | NUMBER { $$ = tfs_add_number(sb, $1); CHECK_RETURN_PTR($$); } 158 | ; 159 | 160 | 161 | compare : 162 | field '<' val { $$ = tfs_add_filter(sb, $1, $3, FILTER_LT); CHECK_RETURN_PTR($$); } 163 | | field '>' val { $$ = tfs_add_filter(sb, $1, $3, FILTER_GT); CHECK_RETURN_PTR($$); } 164 | | field LE val { $$ = tfs_add_filter(sb, $1, $3, FILTER_LE); CHECK_RETURN_PTR($$); } 165 | | field GE val { $$ = tfs_add_filter(sb, $1, $3, FILTER_GE); CHECK_RETURN_PTR($$); } 166 | | field '=' val { $$ = tfs_add_filter(sb, $1, $3, FILTER_EQ); CHECK_RETURN_PTR($$); } 167 | | field EQ val { $$ = tfs_add_filter(sb, $1, $3, FILTER_EQ); CHECK_RETURN_PTR($$); } 168 | | field NEQ val { $$ = tfs_add_filter(sb, $1, $3, FILTER_NE); CHECK_RETURN_PTR($$); } 169 | | field "!=" val { $$ = tfs_add_filter(sb, $1, $3, FILTER_NE); CHECK_RETURN_PTR($$); } 170 | | field '&' val { $$ = tfs_add_filter(sb, $1, $3, FILTER_BIN_AND); CHECK_RETURN_PTR($$); } 171 | | field '~' str_val { $$ = tfs_add_filter(sb, $1, $3, FILTER_STR_CMP); CHECK_RETURN_PTR($$); } 172 | ; 173 | 174 | compare_and_or : 175 | compare_and_or OR compare_and_or { $$ = tfs_add_filter(sb, $1, $3, FILTER_OR); CHECK_RETURN_PTR($$); } 176 | | compare_and_or AND compare_and_or { $$ = tfs_add_filter(sb, $1, $3, FILTER_AND); CHECK_RETURN_PTR($$); } 177 | | '!' '(' compare_and_or ')' { $$ = tfs_add_filter(sb, $3, NULL, FILTER_NOT_GROUP); CHECK_RETURN_PTR($$); } 178 | | '!' compare { $$ = tfs_add_filter(sb, $2, NULL, FILTER_NOT_GROUP); CHECK_RETURN_PTR($$); } 179 | | compare 180 | ; 181 | 182 | compare_items : 183 | compare_items OR compare_items { $$ = tfs_add_filter(sb, $1, $3, FILTER_OR); CHECK_RETURN_PTR($$); } 184 | | '(' compare_and_or ')' { $$ = tfs_add_filter(sb, $2, NULL, FILTER_GROUP); CHECK_RETURN_PTR($$); } 185 | | '!' '(' compare_and_or ')' { $$ = tfs_add_filter(sb, $3, NULL, FILTER_NOT_GROUP); CHECK_RETURN_PTR($$); } 186 | | '!' compare { $$ = tfs_add_filter(sb, $2, NULL, FILTER_NOT_GROUP); CHECK_RETURN_PTR($$); } 187 | | compare 188 | ; 189 | 190 | compare_cmds : 191 | compare_items { CHECK_RETURN_VAL(tfs_add_where(sb, $1)); } 192 | ; 193 | 194 | /* 195 | * Top level AND is equal to ',' but the compare_cmds in them must 196 | * all be of for the same event (start or end exclusive). 197 | * That is, OR is not to be used between start and end events. 198 | */ 199 | compare_list : 200 | compare_cmds 201 | | compare_cmds ',' compare_list 202 | | compare_cmds AND compare_list 203 | ; 204 | 205 | where_clause : 206 | WHERE compare_list 207 | ; 208 | 209 | opt_where_clause : 210 | /* empty */ 211 | | where_clause 212 | ; 213 | 214 | opt_join_clause : 215 | /* empty set */ 216 | | join_clause 217 | ; 218 | 219 | table_exp : 220 | from_clause opt_join_clause opt_where_clause 221 | ; 222 | 223 | from_clause : 224 | FROM item { CHECK_RETURN_VAL(tfs_add_from(sb, $2)); } 225 | 226 | /* 227 | * Select from a from clause confuses the variable parsing. 228 | * disable it for now. 229 | 230 | | FROM '(' select_statement ')' label 231 | { 232 | from_table_end($5); 233 | $$ = store_printf("FROM (%s) AS %s", $3, $5); 234 | } 235 | */ 236 | ; 237 | 238 | join_clause : 239 | JOIN item ON match_clause { tfs_add_to(sb, $2); } 240 | ; 241 | 242 | match : 243 | item '=' item { CHECK_RETURN_VAL(tfs_add_match(sb, $1, $3)); } 244 | | item EQ item { CHECK_RETURN_VAL(tfs_add_match(sb, $1, $3)); } 245 | 246 | ; 247 | 248 | match_clause : 249 | match 250 | | match ',' match_clause 251 | ; 252 | 253 | %% 254 | -------------------------------------------------------------------------------- /src/tracefs-eprobes.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.1 2 | /* 3 | * Copyright (C) 2021, VMware, Tzvetomir Stoyanov 4 | * 5 | */ 6 | #include 7 | #include 8 | 9 | #include "tracefs.h" 10 | #include "tracefs-local.h" 11 | 12 | #define EPROBE_DEFAULT_GROUP "eprobes" 13 | 14 | /** 15 | * tracefs_eprobe_alloc - Allocate new eprobe 16 | * @system: The system name (NULL for the default eprobes) 17 | * @event: The name of the event to create 18 | * @target_system: The system of the target event 19 | * @target_event: The name of the target event 20 | * @fetchargs: String with arguments, that will be fetched from @target_event 21 | * 22 | * Allocate an eprobe context that will be in the @system group (or eprobes if 23 | * @system is NULL). Have the name of @event. The new eprobe will be attached to 24 | * given @target_event which is in the given @target_system. The arguments 25 | * described in @fetchargs will fetched from the @target_event. 26 | * 27 | * The eprobe is not created in the system. 28 | * 29 | * Return a pointer to a eprobe context on success, or NULL on error. 30 | * The returned pointer must be freed with tracefs_dynevent_free() 31 | * 32 | */ 33 | struct tracefs_dynevent * 34 | tracefs_eprobe_alloc(const char *system, const char *event, 35 | const char *target_system, const char *target_event, const char *fetchargs) 36 | { 37 | struct tracefs_dynevent *kp; 38 | char *target; 39 | 40 | if (!event || !target_system || !target_event) { 41 | errno = EINVAL; 42 | return NULL; 43 | } 44 | 45 | if (!system) 46 | system = EPROBE_DEFAULT_GROUP; 47 | 48 | if (asprintf(&target, "%s.%s", target_system, target_event) < 0) 49 | return NULL; 50 | 51 | kp = tfs_dynevent_alloc(TRACEFS_DYNEVENT_EPROBE, system, event, target, fetchargs); 52 | free(target); 53 | 54 | return kp; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/tracefs-marker.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.1 2 | /* 3 | * Copyright (C) 2021, VMware, Tzvetomir Stoyanov 4 | * 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "tracefs.h" 13 | #include "tracefs-local.h" 14 | 15 | /* File descriptors for Top level trace markers */ 16 | static int ftrace_marker_fd = -1; 17 | static int ftrace_marker_raw_fd = -1; 18 | 19 | static inline int *get_marker_fd(struct tracefs_instance *instance, bool raw) 20 | { 21 | if (raw) 22 | return instance ? &instance->ftrace_marker_raw_fd : &ftrace_marker_raw_fd; 23 | return instance ? &instance->ftrace_marker_fd : &ftrace_marker_fd; 24 | } 25 | 26 | static int marker_init(struct tracefs_instance *instance, bool raw) 27 | { 28 | const char *file = raw ? "trace_marker_raw" : "trace_marker"; 29 | pthread_mutex_t *lock = trace_get_lock(instance); 30 | int *fd = get_marker_fd(instance, raw); 31 | int ret; 32 | 33 | if (*fd >= 0) 34 | return 0; 35 | 36 | /* 37 | * The mutex is only to hold the integrity of the file descriptor 38 | * to prevent opening it more than once, or closing the same 39 | * file descriptor more than once. It does not protect against 40 | * one thread closing the file descriptor and another thread 41 | * writing to it. That is up to the application to prevent 42 | * from happening. 43 | */ 44 | pthread_mutex_lock(lock); 45 | /* The file could have been opened since we taken the lock */ 46 | if (*fd < 0) 47 | *fd = tracefs_instance_file_open(instance, file, O_WRONLY | O_CLOEXEC); 48 | 49 | ret = *fd < 0 ? -1 : 0; 50 | pthread_mutex_unlock(lock); 51 | 52 | return ret; 53 | } 54 | 55 | static void marker_close(struct tracefs_instance *instance, bool raw) 56 | { 57 | pthread_mutex_t *lock = trace_get_lock(instance); 58 | int *fd = get_marker_fd(instance, raw); 59 | 60 | pthread_mutex_lock(lock); 61 | if (*fd >= 0) { 62 | close(*fd); 63 | *fd = -1; 64 | } 65 | pthread_mutex_unlock(lock); 66 | } 67 | 68 | static int marker_write(struct tracefs_instance *instance, bool raw, void *data, int len) 69 | { 70 | int *fd = get_marker_fd(instance, raw); 71 | int ret; 72 | 73 | /* 74 | * The lock does not need to be taken for writes. As a write 75 | * does not modify the file descriptor. It's up to the application 76 | * to prevent it from being closed if another thread is doing a write. 77 | */ 78 | if (!data || len < 1) 79 | return -1; 80 | if (*fd < 0) { 81 | ret = marker_init(instance, raw); 82 | if (ret < 0) 83 | return ret; 84 | } 85 | 86 | ret = write(*fd, data, len); 87 | 88 | return ret == len ? 0 : -1; 89 | } 90 | 91 | /** 92 | * tracefs_print_init - Open trace marker of selected instance for writing 93 | * @instance: ftrace instance, can be NULL for top tracing instance. 94 | * 95 | * Returns 0 if the trace marker is opened successfully, or -1 in case of an error 96 | */ 97 | int tracefs_print_init(struct tracefs_instance *instance) 98 | { 99 | return marker_init(instance, false); 100 | } 101 | 102 | /** 103 | * tracefs_vprintf - Write a formatted string in the trace marker 104 | * @instance: ftrace instance, can be NULL for top tracing instance. 105 | * @fmt: pritnf formatted string 106 | * @ap: list of arguments for the formatted string 107 | * 108 | * If the trace marker of the desired instance is not open already, 109 | * this API will open it for writing. It will stay open until 110 | * tracefs_print_close() is called. 111 | * 112 | * Returns 0 if the string is written correctly, or -1 in case of an error 113 | */ 114 | int tracefs_vprintf(struct tracefs_instance *instance, const char *fmt, va_list ap) 115 | { 116 | char *str = NULL; 117 | int ret; 118 | 119 | ret = vasprintf(&str, fmt, ap); 120 | if (ret < 0) 121 | return ret; 122 | ret = marker_write(instance, false, str, strlen(str)); 123 | free(str); 124 | 125 | return ret; 126 | } 127 | 128 | /** 129 | * tracefs_printf - Write a formatted string in the trace marker 130 | * @instance: ftrace instance, can be NULL for top tracing instance. 131 | * @fmt: pritnf formatted string with variable arguments ... 132 | * 133 | * If the trace marker of the desired instance is not open already, 134 | * this API will open it for writing. It will stay open until 135 | * tracefs_print_close() is called. 136 | * 137 | * Returns 0 if the string is written correctly, or -1 in case of an error 138 | */ 139 | int tracefs_printf(struct tracefs_instance *instance, const char *fmt, ...) 140 | { 141 | va_list ap; 142 | int ret; 143 | 144 | va_start(ap, fmt); 145 | ret = tracefs_vprintf(instance, fmt, ap); 146 | va_end(ap); 147 | 148 | return ret; 149 | } 150 | 151 | /** 152 | * tracefs_print_close - Close trace marker of selected instance 153 | * @instance: ftrace instance, can be NULL for top tracing instance. 154 | * 155 | * Closes the trace marker, previously opened with any of the other tracefs_print APIs 156 | */ 157 | void tracefs_print_close(struct tracefs_instance *instance) 158 | { 159 | marker_close(instance, false); 160 | } 161 | 162 | /** 163 | * tracefs_binary_init - Open raw trace marker of selected instance for writing 164 | * @instance: ftrace instance, can be NULL for top tracing instance. 165 | * 166 | * Returns 0 if the raw trace marker is opened successfully, or -1 in case of an error 167 | */ 168 | int tracefs_binary_init(struct tracefs_instance *instance) 169 | { 170 | return marker_init(instance, true); 171 | } 172 | 173 | /** 174 | * tracefs_binary_write - Write binary data in the raw trace marker 175 | * @instance: ftrace instance, can be NULL for top tracing instance. 176 | * @data: binary data, that is going to be written in the trace marker 177 | * @len: length of the @data 178 | * 179 | * If the raw trace marker of the desired instance is not open already, 180 | * this API will open it for writing. It will stay open until 181 | * tracefs_binary_close() is called. 182 | * 183 | * Returns 0 if the data is written correctly, or -1 in case of an error 184 | */ 185 | int tracefs_binary_write(struct tracefs_instance *instance, void *data, int len) 186 | { 187 | return marker_write(instance, true, data, len); 188 | } 189 | 190 | /** 191 | * tracefs_binary_close - Close raw trace marker of selected instance 192 | * @instance: ftrace instance, can be NULL for top tracing instance. 193 | * 194 | * Closes the raw trace marker, previously opened with any of the other tracefs_binary APIs 195 | */ 196 | void tracefs_binary_close(struct tracefs_instance *instance) 197 | { 198 | marker_close(instance, true); 199 | } 200 | -------------------------------------------------------------------------------- /src/tracefs-mmap.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.1 2 | /* 3 | * Copyright (C) 2023 Google Inc, Steven Rostedt 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "tracefs-local.h" 11 | 12 | /** 13 | * struct trace_buffer_meta - Ring-buffer Meta-page description 14 | * @meta_page_size: Size of this meta-page. 15 | * @meta_struct_len: Size of this structure. 16 | * @subbuf_size: Size of each sub-buffer. 17 | * @nr_subbufs: Number of subbfs in the ring-buffer, including the reader. 18 | * @reader.lost_events: Number of events lost at the time of the reader swap. 19 | * @reader.id: subbuf ID of the current reader. ID range [0 : @nr_subbufs - 1] 20 | * @reader.read: Number of bytes read on the reader subbuf. 21 | * @flags: Placeholder for now, 0 until new features are supported. 22 | * @entries: Number of entries in the ring-buffer. 23 | * @overrun: Number of entries lost in the ring-buffer. 24 | * @read: Number of entries that have been read. 25 | * @Reserved1: Internal use only. 26 | * @Reserved2: Internal use only. 27 | */ 28 | struct trace_buffer_meta { 29 | __u32 meta_page_size; 30 | __u32 meta_struct_len; 31 | 32 | __u32 subbuf_size; 33 | __u32 nr_subbufs; 34 | 35 | struct { 36 | __u64 lost_events; 37 | __u32 id; 38 | __u32 read; 39 | } reader; 40 | 41 | __u64 flags; 42 | 43 | __u64 entries; 44 | __u64 overrun; 45 | __u64 read; 46 | 47 | __u64 Reserved1; 48 | __u64 Reserved2; 49 | }; 50 | 51 | #define TRACE_MMAP_IOCTL_GET_READER _IO('R', 0x20) 52 | 53 | struct trace_mmap { 54 | struct trace_buffer_meta *map; 55 | struct kbuffer *kbuf; 56 | void *data; 57 | int *data_pages; 58 | int fd; 59 | int last_idx; 60 | int last_read; 61 | int meta_len; 62 | int data_len; 63 | }; 64 | 65 | /** 66 | * tfs_mmap - try to mmap the ring buffer 67 | * @fd: The file descriptor to the trace_pipe_raw file 68 | * @kbuf: The kbuffer to load the subbuffer to 69 | * 70 | * Will try to mmap the ring buffer if it is supported, and 71 | * if not, will return NULL, otherwise it returns a descriptor 72 | * to handle the mapping. 73 | */ 74 | __hidden void *tfs_mmap(int fd, struct kbuffer *kbuf) 75 | { 76 | struct trace_mmap *tmap; 77 | int page_size; 78 | void *meta; 79 | void *data; 80 | 81 | page_size = getpagesize(); 82 | meta = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); 83 | if (meta == MAP_FAILED) 84 | return NULL; 85 | 86 | tmap = calloc(1, sizeof(*tmap)); 87 | if (!tmap) { 88 | munmap(meta, page_size); 89 | return NULL; 90 | } 91 | 92 | tmap->kbuf = kbuffer_dup(kbuf); 93 | if (!tmap->kbuf) { 94 | munmap(meta, page_size); 95 | free(tmap); 96 | } 97 | kbuf = tmap->kbuf; 98 | 99 | tmap->fd = fd; 100 | 101 | tmap->map = meta; 102 | tmap->meta_len = tmap->map->meta_page_size; 103 | 104 | if (tmap->meta_len > page_size) { 105 | munmap(meta, page_size); 106 | meta = mmap(NULL, tmap->meta_len, PROT_READ, MAP_SHARED, fd, 0); 107 | if (meta == MAP_FAILED) { 108 | kbuffer_free(kbuf); 109 | free(tmap); 110 | return NULL; 111 | } 112 | tmap->map = meta; 113 | } 114 | 115 | tmap->data_pages = meta + tmap->meta_len; 116 | 117 | tmap->data_len = tmap->map->subbuf_size * tmap->map->nr_subbufs; 118 | 119 | tmap->data = mmap(NULL, tmap->data_len, PROT_READ, MAP_SHARED, 120 | fd, tmap->meta_len); 121 | if (tmap->data == MAP_FAILED) { 122 | munmap(meta, tmap->meta_len); 123 | kbuffer_free(kbuf); 124 | free(tmap); 125 | return NULL; 126 | } 127 | 128 | tmap->last_idx = tmap->map->reader.id; 129 | 130 | data = tmap->data + tmap->map->subbuf_size * tmap->last_idx; 131 | kbuffer_load_subbuffer(kbuf, data); 132 | 133 | /* 134 | * The page could have left over data on it that was already 135 | * consumed. Move the "read" forward in that case. 136 | */ 137 | if (tmap->map->reader.read) { 138 | int size = kbuffer_start_of_data(kbuf) + tmap->map->reader.read; 139 | char tmpbuf[size]; 140 | kbuffer_read_buffer(kbuf, tmpbuf, size); 141 | } 142 | 143 | return tmap; 144 | } 145 | 146 | __hidden void tfs_unmap(void *mapping) 147 | { 148 | struct trace_mmap *tmap = mapping; 149 | 150 | if (!tmap) 151 | return; 152 | 153 | munmap(tmap->data, tmap->data_len); 154 | munmap(tmap->map, tmap->meta_len); 155 | kbuffer_free(tmap->kbuf); 156 | free(tmap); 157 | } 158 | 159 | static int get_reader(struct trace_mmap *tmap) 160 | { 161 | return ioctl(tmap->fd, TRACE_MMAP_IOCTL_GET_READER); 162 | } 163 | 164 | __hidden int tfs_mmap_load_subbuf(void *mapping, struct kbuffer *kbuf) 165 | { 166 | struct trace_mmap *tmap = mapping; 167 | void *data; 168 | int id; 169 | 170 | if (!tmap) 171 | return -1; 172 | 173 | id = tmap->map->reader.id; 174 | data = tmap->data + tmap->map->subbuf_size * id; 175 | 176 | /* 177 | * If kbuf doesn't point to the current sub-buffer 178 | * just load it and return. 179 | */ 180 | if (data != kbuffer_subbuffer(kbuf)) { 181 | kbuffer_load_subbuffer(kbuf, data); 182 | /* Move the read pointer forward if need be */ 183 | if (kbuffer_curr_index(tmap->kbuf)) { 184 | int size = kbuffer_curr_offset(tmap->kbuf); 185 | char tmpbuf[size]; 186 | kbuffer_read_buffer(kbuf, tmpbuf, size); 187 | } 188 | return 1; 189 | } 190 | 191 | /* 192 | * Perhaps the reader page had a write that added 193 | * more data. 194 | */ 195 | kbuffer_refresh(kbuf); 196 | 197 | /* Are there still events to read? */ 198 | if (kbuffer_curr_size(kbuf)) { 199 | /* If current is greater than what was read, refresh */ 200 | if (kbuffer_curr_offset(kbuf) + kbuffer_curr_size(kbuf) > 201 | tmap->map->reader.read) { 202 | if (get_reader(tmap) < 0) 203 | return -1; 204 | } 205 | return 1; 206 | } 207 | 208 | /* See if a new page is ready? */ 209 | if (get_reader(tmap) < 0) 210 | return -1; 211 | id = tmap->map->reader.id; 212 | data = tmap->data + tmap->map->subbuf_size * id; 213 | 214 | /* 215 | * If the sub-buffer hasn't changed, then there's no more 216 | * events to read. 217 | */ 218 | if (data == kbuffer_subbuffer(kbuf)) 219 | return 0; 220 | 221 | kbuffer_load_subbuffer(kbuf, data); 222 | return 1; 223 | } 224 | 225 | __hidden int tfs_mmap_read(void *mapping, void *buffer) 226 | { 227 | struct trace_mmap *tmap = mapping; 228 | struct kbuffer *kbuf; 229 | int ret; 230 | 231 | if (!tmap) 232 | return -1; 233 | 234 | kbuf = tmap->kbuf; 235 | 236 | ret = tfs_mmap_load_subbuf(mapping, kbuf); 237 | /* Return for error or no more events */ 238 | if (ret <= 0) 239 | return ret; 240 | 241 | /* Update the buffer */ 242 | ret = kbuffer_read_buffer(kbuf, buffer, tmap->map->subbuf_size); 243 | if (ret <= 0) 244 | return ret; 245 | 246 | /* This needs to include the size of the meta data too */ 247 | return ret + kbuffer_start_of_data(kbuf); 248 | } 249 | -------------------------------------------------------------------------------- /src/tracefs-perf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | static void perf_init_pe(struct perf_event_attr *pe) 10 | { 11 | memset(pe, 0, sizeof(struct perf_event_attr)); 12 | pe->type = PERF_TYPE_SOFTWARE; 13 | pe->sample_type = PERF_SAMPLE_CPU; 14 | pe->size = sizeof(struct perf_event_attr); 15 | pe->config = PERF_COUNT_HW_CPU_CYCLES; 16 | pe->disabled = 1; 17 | pe->exclude_kernel = 1; 18 | pe->freq = 1; 19 | pe->sample_freq = 1000; 20 | pe->inherit = 1; 21 | pe->mmap = 1; 22 | pe->comm = 1; 23 | pe->task = 1; 24 | pe->precise_ip = 1; 25 | pe->sample_id_all = 1; 26 | pe->read_format = PERF_FORMAT_ID | 27 | PERF_FORMAT_TOTAL_TIME_ENABLED| 28 | PERF_FORMAT_TOTAL_TIME_RUNNING; 29 | 30 | } 31 | 32 | static long perf_event_open(struct perf_event_attr *event, pid_t pid, 33 | int cpu, int group_fd, unsigned long flags) 34 | { 35 | return syscall(__NR_perf_event_open, event, pid, cpu, group_fd, flags); 36 | } 37 | 38 | #define MAP_SIZE (9 * getpagesize()) 39 | 40 | static struct perf_event_mmap_page *perf_mmap(int fd) 41 | { 42 | struct perf_event_mmap_page *perf_mmap; 43 | 44 | /* associate a buffer with the file */ 45 | perf_mmap = mmap(NULL, MAP_SIZE, 46 | PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 47 | if (perf_mmap == MAP_FAILED) 48 | return NULL; 49 | 50 | return perf_mmap; 51 | } 52 | 53 | static int perf_read_maps(int cpu, int *shift, int *mult, long long *offset) 54 | { 55 | struct perf_event_attr perf_attr; 56 | struct perf_event_mmap_page *mpage; 57 | int fd; 58 | 59 | /* We succeed if theres' nothing to do! */ 60 | if (!shift && !mult && !offset) 61 | return 0; 62 | 63 | perf_init_pe(&perf_attr); 64 | fd = perf_event_open(&perf_attr, getpid(), cpu, -1, 0); 65 | if (fd < 0) 66 | return -1; 67 | 68 | mpage = perf_mmap(fd); 69 | if (!mpage) { 70 | close(fd); 71 | return -1; 72 | } 73 | 74 | if (shift) 75 | *shift = mpage->time_shift; 76 | if (mult) 77 | *mult = mpage->time_mult; 78 | if (offset) 79 | *offset = mpage->time_offset; 80 | munmap(mpage, MAP_SIZE); 81 | return 0; 82 | } 83 | 84 | /** 85 | * tracefs_time_conversion - Find how the kernel converts the raw counters 86 | * @cpu: The CPU to check for 87 | * @shift: If non-NULL it will be set to the shift value 88 | * @mult: If non-NULL it will be set to the multiplier value 89 | * @offset: If non-NULL it will be set to the offset 90 | */ 91 | int tracefs_time_conversion(int cpu, int *shift, int *mult, long long *offset) 92 | { 93 | return perf_read_maps(cpu, shift, mult, offset); 94 | } 95 | -------------------------------------------------------------------------------- /src/tracefs-stats.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.1 2 | /* 3 | * Copyright (C) 2023 Google LLC, Steven Rostedt 4 | */ 5 | #include 6 | #include 7 | #include "tracefs.h" 8 | #include "tracefs-local.h" 9 | 10 | static long long convert_ts(char *value) 11 | { 12 | long long ts; 13 | char *saveptr; 14 | char *secs; 15 | char *usecs; 16 | 17 | secs = strtok_r(value, ".", &saveptr); 18 | if (!secs) 19 | return -1LL; 20 | 21 | ts = strtoll(secs, NULL, 0); 22 | 23 | usecs = strtok_r(NULL, ".", &saveptr); 24 | if (!usecs) 25 | return ts; 26 | 27 | /* Could be in nanoseconds */ 28 | if (strlen(usecs) > 6) 29 | ts *= 1000000000LL; 30 | else 31 | ts *= 1000000LL; 32 | 33 | ts += strtoull(usecs, NULL, 0); 34 | 35 | return ts; 36 | } 37 | 38 | struct tracefs_buffer_stat * 39 | tracefs_instance_get_stat(struct tracefs_instance *instance, int cpu) 40 | { 41 | struct tracefs_buffer_stat *tstat; 42 | char *saveptr; 43 | char *value; 44 | char *field; 45 | char *path; 46 | char *line; 47 | char *next; 48 | char *buf; 49 | int len; 50 | int ret; 51 | 52 | ret = asprintf(&path, "per_cpu/cpu%d/stats", cpu); 53 | if (ret < 0) 54 | return NULL; 55 | 56 | buf = tracefs_instance_file_read(instance, path, &len); 57 | free(path); 58 | 59 | if (!buf) 60 | return NULL; 61 | 62 | tstat = malloc(sizeof(*tstat)); 63 | if (!tstat) { 64 | free(buf); 65 | return NULL; 66 | } 67 | 68 | /* Set everything to -1 */ 69 | memset(tstat, -1, sizeof(*tstat)); 70 | 71 | next = buf; 72 | while ((line = strtok_r(next, "\n", &saveptr))) { 73 | char *save2; 74 | 75 | next = NULL; 76 | 77 | field = strtok_r(line, ":", &save2); 78 | if (!field) 79 | break; 80 | 81 | value = strtok_r(NULL, ":", &save2); 82 | if (!value) 83 | break; 84 | 85 | while (isspace(*value)) 86 | value++; 87 | 88 | if (strcmp(field, "entries") == 0) { 89 | tstat->entries = strtoull(value, NULL, 0); 90 | 91 | } else if (strcmp(field, "overrun") == 0) { 92 | tstat->overrun = strtoull(value, NULL, 0); 93 | 94 | } else if (strcmp(field, "commit overrun") == 0) { 95 | tstat->commit_overrun = strtoull(value, NULL, 0); 96 | 97 | } else if (strcmp(field, "bytes") == 0) { 98 | tstat->bytes = strtoull(value, NULL, 0); 99 | 100 | } else if (strcmp(field, "oldest event ts") == 0) { 101 | tstat->oldest_ts = convert_ts(value); 102 | 103 | } else if (strcmp(field, "now ts") == 0) { 104 | tstat->now_ts = convert_ts(value); 105 | 106 | } else if (strcmp(field, "dropped events") == 0) { 107 | tstat->dropped_events = strtoull(value, NULL, 0); 108 | 109 | } else if (strcmp(field, "read events") == 0) { 110 | tstat->read_events = strtoull(value, NULL, 0); 111 | } 112 | } 113 | free(buf); 114 | 115 | return tstat; 116 | } 117 | 118 | void tracefs_instance_put_stat(struct tracefs_buffer_stat *tstat) 119 | { 120 | free(tstat); 121 | } 122 | 123 | ssize_t tracefs_buffer_stat_entries(struct tracefs_buffer_stat *tstat) 124 | { 125 | return tstat->entries; 126 | } 127 | 128 | ssize_t tracefs_buffer_stat_overrun(struct tracefs_buffer_stat *tstat) 129 | { 130 | return tstat->overrun; 131 | } 132 | 133 | ssize_t tracefs_buffer_stat_commit_overrun(struct tracefs_buffer_stat *tstat) 134 | { 135 | return tstat->commit_overrun; 136 | } 137 | 138 | ssize_t tracefs_buffer_stat_bytes(struct tracefs_buffer_stat *tstat) 139 | { 140 | return tstat->bytes; 141 | } 142 | 143 | long long tracefs_buffer_stat_event_timestamp(struct tracefs_buffer_stat *tstat) 144 | { 145 | return tstat->oldest_ts; 146 | } 147 | 148 | long long tracefs_buffer_stat_timestamp(struct tracefs_buffer_stat *tstat) 149 | { 150 | return tstat->now_ts; 151 | } 152 | 153 | ssize_t tracefs_buffer_stat_dropped_events(struct tracefs_buffer_stat *tstat) 154 | { 155 | return tstat->dropped_events; 156 | } 157 | 158 | ssize_t tracefs_buffer_stat_read_events(struct tracefs_buffer_stat *tstat) 159 | { 160 | return tstat->read_events; 161 | } 162 | 163 | -------------------------------------------------------------------------------- /src/tracefs-uprobes.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.1 2 | /* 3 | * Copyright (C) 2022, VMware, Tzvetomir Stoyanov 4 | * 5 | */ 6 | #include 7 | #include 8 | 9 | #include "tracefs.h" 10 | #include "tracefs-local.h" 11 | 12 | #define UPROBE_DEFAULT_GROUP "uprobes" 13 | 14 | static struct tracefs_dynevent * 15 | uprobe_alloc(enum tracefs_dynevent_type type, const char *system, const char *event, 16 | const char *file, unsigned long long offset, const char *fetchargs) 17 | { 18 | struct tracefs_dynevent *kp; 19 | char *target; 20 | 21 | if (!event || !file) { 22 | errno = EINVAL; 23 | return NULL; 24 | } 25 | 26 | if (!system) 27 | system = UPROBE_DEFAULT_GROUP; 28 | 29 | if (asprintf(&target, "%s:0x%0*llx", file, (int)(sizeof(void *) * 2), offset) < 0) 30 | return NULL; 31 | 32 | kp = tfs_dynevent_alloc(type, system, event, target, fetchargs); 33 | free(target); 34 | 35 | return kp; 36 | } 37 | 38 | /** 39 | * tracefs_uprobe_alloc - Allocate new user probe (uprobe) 40 | * @system: The system name (NULL for the default uprobes) 41 | * @event: The name of the event to create 42 | * @file: The full path to the binary file, where the uprobe will be set 43 | * @offset: Offset within the @file 44 | * @fetchargs: String with arguments, that will be fetched with the uprobe 45 | * 46 | * Allocate new uprobe context that will be in the @system group 47 | * (or uprobes if @system is NULL) and with @event name. The new uprobe will be 48 | * attached to @offset within the @file. The arguments described in @fetchargs 49 | * will fetched with the uprobe. See linux/Documentation/trace/uprobetracer.rst 50 | * for more details. 51 | * 52 | * The uprobe is not created in the system. 53 | * 54 | * Return a pointer to a uprobe context on success, or NULL on error. 55 | * The returned pointer must be freed with tracefs_dynevent_free() 56 | * 57 | */ 58 | struct tracefs_dynevent * 59 | tracefs_uprobe_alloc(const char *system, const char *event, 60 | const char *file, unsigned long long offset, const char *fetchargs) 61 | { 62 | return uprobe_alloc(TRACEFS_DYNEVENT_UPROBE, system, event, file, offset, fetchargs); 63 | } 64 | 65 | /** 66 | * tracefs_uretprobe_alloc - Allocate new user return probe (uretprobe) 67 | * @system: The system name (NULL for the default uprobes) 68 | * @event: The name of the event to create 69 | * @file: The full path to the binary file, where the uretprobe will be set 70 | * @offset: Offset within the @file 71 | * @fetchargs: String with arguments, that will be fetched with the uretprobe 72 | * 73 | * Allocate mew uretprobe context that will be in the @system group 74 | * (or uprobes if @system is NULL) and with @event name. The new uretprobe will 75 | * be attached to @offset within the @file. The arguments described in @fetchargs 76 | * will fetched with the uprobe. See linux/Documentation/trace/uprobetracer.rst 77 | * for more details. 78 | * 79 | * The uretprobe is not created in the system. 80 | * 81 | * Return a pointer to a uretprobe context on success, or NULL on error. 82 | * The returned pointer must be freed with tracefs_dynevent_free() 83 | * 84 | */ 85 | struct tracefs_dynevent * 86 | tracefs_uretprobe_alloc(const char *system, const char *event, 87 | const char *file, unsigned long long offset, const char *fetchargs) 88 | { 89 | return uprobe_alloc(TRACEFS_DYNEVENT_URETPROBE, system, event, file, offset, fetchargs); 90 | } 91 | -------------------------------------------------------------------------------- /src/tracefs-vsock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | static int open_vsock(unsigned int cid, unsigned int port) 10 | { 11 | struct sockaddr_vm addr = { 12 | .svm_family = AF_VSOCK, 13 | .svm_cid = cid, 14 | .svm_port = port, 15 | }; 16 | int sd; 17 | 18 | sd = socket(AF_VSOCK, SOCK_STREAM, 0); 19 | if (sd < 0) 20 | return -1; 21 | 22 | if (connect(sd, (struct sockaddr *)&addr, sizeof(addr))) { 23 | close(sd); 24 | return -1; 25 | } 26 | 27 | return sd; 28 | } 29 | 30 | struct pids { 31 | struct pids *next; 32 | int pid; 33 | }; 34 | 35 | struct trace_info { 36 | struct tracefs_instance *instance; 37 | struct tep_handle *tep; 38 | struct tep_event *wake_up; 39 | struct tep_event *kvm_exit; 40 | struct tep_format_field *wake_pid; 41 | struct pids *pids; 42 | int pid; 43 | }; 44 | 45 | static void tear_down_trace(struct trace_info *info) 46 | { 47 | tracefs_event_disable(info->instance, NULL, NULL); 48 | tep_free(info->tep); 49 | info->tep = NULL; 50 | } 51 | 52 | static int add_pid(struct pids **pids, int pid) 53 | { 54 | struct pids *new_pid; 55 | 56 | new_pid = malloc(sizeof(*new_pid)); 57 | if (!new_pid) 58 | return -1; 59 | 60 | new_pid->pid = pid; 61 | new_pid->next = *pids; 62 | *pids = new_pid; 63 | return 0; 64 | } 65 | 66 | static bool match_pid(struct pids *pids, int pid) 67 | { 68 | while (pids) { 69 | if (pids->pid == pid) 70 | return true; 71 | pids = pids->next; 72 | } 73 | return false; 74 | } 75 | 76 | static int waking_callback(struct tep_event *event, struct tep_record *record, 77 | int cpu, void *data) 78 | { 79 | struct trace_info *info = data; 80 | unsigned long long val; 81 | int flags; 82 | int pid; 83 | int ret; 84 | 85 | pid = tep_data_pid(event->tep, record); 86 | if (!match_pid(info->pids, pid)) 87 | return 0; 88 | 89 | /* Ignore wakeups in interrupts */ 90 | flags = tep_data_flags(event->tep, record); 91 | if (flags & (TRACE_FLAG_HARDIRQ | TRACE_FLAG_SOFTIRQ)) 92 | return 0; 93 | 94 | if (!info->wake_pid) { 95 | info->wake_pid = tep_find_field(event, "pid"); 96 | 97 | if (!info->wake_pid) 98 | return -1; 99 | } 100 | 101 | ret = tep_read_number_field(info->wake_pid, record->data, &val); 102 | if (ret < 0) 103 | return -1; 104 | 105 | return add_pid(&info->pids, (int)val); 106 | } 107 | 108 | static int exit_callback(struct tep_event *event, struct tep_record *record, 109 | int cpu, void *data) 110 | { 111 | struct trace_info *info = data; 112 | int pid; 113 | 114 | pid = tep_data_pid(event->tep, record); 115 | if (!match_pid(info->pids, pid)) 116 | return 0; 117 | 118 | info->pid = pid; 119 | 120 | /* Found the pid we are looking for, stop the trace */ 121 | return -1; 122 | } 123 | 124 | static int setup_trace(struct trace_info *info) 125 | { 126 | const char *systems[] = { "sched", "kvm", NULL}; 127 | int ret; 128 | 129 | info->pids = NULL; 130 | 131 | tracefs_trace_off(info->instance); 132 | info->tep = tracefs_local_events_system(NULL, systems); 133 | if (!info->tep) 134 | return -1; 135 | 136 | /* 137 | * Follow the wake ups, starting with this pid, to find 138 | * the one that exits to the guest. That will be the thread 139 | * of the vCPU of the guest. 140 | */ 141 | ret = tracefs_follow_event(info->tep, info->instance, 142 | "sched", "sched_waking", 143 | waking_callback, info); 144 | if (ret < 0) 145 | goto fail; 146 | 147 | ret = tracefs_follow_event(info->tep, info->instance, 148 | "kvm", "kvm_exit", 149 | exit_callback, info); 150 | if (ret < 0) 151 | goto fail; 152 | 153 | ret = tracefs_event_enable(info->instance, "sched", "sched_waking"); 154 | if (ret < 0) 155 | goto fail; 156 | 157 | ret = tracefs_event_enable(info->instance, "kvm", "kvm_exit"); 158 | if (ret < 0) 159 | goto fail; 160 | 161 | return 0; 162 | fail: 163 | tear_down_trace(info); 164 | return -1; 165 | } 166 | 167 | 168 | static void free_pids(struct pids *pids) 169 | { 170 | struct pids *next; 171 | 172 | while (pids) { 173 | next = pids; 174 | pids = pids->next; 175 | free(next); 176 | } 177 | } 178 | 179 | static int find_thread_leader(int pid) 180 | { 181 | FILE *fp; 182 | char *path; 183 | char *save; 184 | char *buf = NULL; 185 | size_t l = 0; 186 | int tgid = -1; 187 | 188 | if (asprintf(&path, "/proc/%d/status", pid) < 0) 189 | return -1; 190 | 191 | fp = fopen(path, "r"); 192 | free(path); 193 | if (!fp) 194 | return -1; 195 | 196 | while (getline(&buf, &l, fp) > 0) { 197 | char *tok; 198 | 199 | if (strncmp(buf, "Tgid:", 5) != 0) 200 | continue; 201 | tok = strtok_r(buf, ":", &save); 202 | if (!tok) 203 | continue; 204 | tok = strtok_r(NULL, ":", &save); 205 | if (!tok) 206 | continue; 207 | while (isspace(*tok)) 208 | tok++; 209 | tgid = strtol(tok, NULL, 0); 210 | break; 211 | } 212 | free(buf); 213 | 214 | return tgid > 0 ? tgid : -1; 215 | } 216 | 217 | int tracefs_instance_find_cid_pid(struct tracefs_instance *instance, int cid) 218 | { 219 | struct trace_info info = {}; 220 | int this_pid = getpid(); 221 | int ret; 222 | int fd; 223 | 224 | info.instance = instance; 225 | 226 | if (setup_trace(&info) < 0) 227 | return -1; 228 | 229 | ret = add_pid(&info.pids, this_pid); 230 | if (ret < 0) 231 | goto out; 232 | 233 | tracefs_instance_file_clear(info.instance, "trace"); 234 | tracefs_trace_on(info.instance); 235 | fd = open_vsock(cid, -1); 236 | tracefs_trace_off(info.instance); 237 | if (fd >= 0) 238 | close(fd); 239 | info.pid = -1; 240 | ret = tracefs_iterate_raw_events(info.tep, info.instance, 241 | NULL, 0, NULL, &info); 242 | if (info.pid <= 0) 243 | ret = -1; 244 | if (ret == 0) 245 | ret = find_thread_leader(info.pid); 246 | 247 | out: 248 | free_pids(info.pids); 249 | info.pids = NULL; 250 | tear_down_trace(&info); 251 | 252 | return ret; 253 | } 254 | 255 | int tracefs_find_cid_pid(int cid) 256 | { 257 | struct tracefs_instance *instance; 258 | char *name; 259 | int ret; 260 | 261 | ret = asprintf(&name, "_tracefs_vsock_find-%d\n", getpid()); 262 | if (ret < 0) 263 | return ret; 264 | 265 | instance = tracefs_instance_create(name); 266 | free(name); 267 | if (!instance) 268 | return -1; 269 | 270 | ret = tracefs_instance_find_cid_pid(instance, cid); 271 | 272 | tracefs_instance_destroy(instance); 273 | tracefs_instance_free(instance); 274 | 275 | return ret; 276 | } 277 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | tracefs_tracing_dir(); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /utest/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1 2 | 3 | include $(src)/scripts/utils.mk 4 | 5 | bdir:=$(obj)/utest 6 | 7 | TARGETS = $(bdir)/trace-utest 8 | 9 | OBJS = 10 | OBJS += trace-utest.o 11 | OBJS += tracefs-utest.o 12 | 13 | LIBS += -lcunit \ 14 | -ldl \ 15 | $(obj)/lib/libtracefs.a 16 | 17 | OBJS := $(OBJS:%.o=$(bdir)/%.o) 18 | 19 | $(bdir): 20 | @mkdir -p $(bdir) 21 | 22 | $(OBJS): | $(bdir) 23 | 24 | $(bdir)/trace-utest: $(OBJS) $(obj)/lib/libtracefs.a 25 | $(Q)$(do_app_build) 26 | 27 | $(bdir)/%.o: %.c 28 | $(Q)$(call do_fpic_compile) 29 | 30 | -include .*.d 31 | 32 | test: $(TARGETS) 33 | 34 | clean: 35 | $(Q)$(call do_clean,$(TARGETS) $(bdir)/*.o $(bdir)/.*.d) 36 | -------------------------------------------------------------------------------- /utest/README: -------------------------------------------------------------------------------- 1 | 2 | Unit tests for tracefs library. The tests use CUnit framework: 3 | http://cunit.sourceforge.net/ 4 | which must be pre installed on the system, before building the unit tests. 5 | The framework can be downloaded, compiled and installed manually, or 6 | using a precompiled distro package: 7 | 8 | Fedora: 9 | CUnit 10 | CUnit-devel 11 | 12 | Ubuntu and Debian: 13 | libcunit1 14 | libcunit1-doc 15 | libcunit1-dev 16 | 17 | openSUSE and SLE: 18 | cunit-devel 19 | -------------------------------------------------------------------------------- /utest/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1 2 | # 3 | # Copyright (c) 2023 Daniel Wagner, SUSE LLC 4 | 5 | source = [ 6 | 'trace-utest.c', 7 | 'tracefs-utest.c', 8 | ] 9 | 10 | e = executable( 11 | 'trace-utest', 12 | source, 13 | include_directories: [incdir], 14 | dependencies: [libtraceevent_dep, threads_dep, cunit_dep], 15 | link_with: libtracefs_static) 16 | 17 | test('trace-utest', e) 18 | -------------------------------------------------------------------------------- /utest/trace-utest.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.1 2 | /* 3 | * Copyright (C) 2020, VMware, Tzvetomir Stoyanov 4 | * 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "trace-utest.h" 16 | 17 | enum unit_tests { 18 | RUN_NONE = 0, 19 | RUN_TRACEFS = (1 << 0), 20 | RUN_ALL = 0xFFFF 21 | }; 22 | 23 | static void print_help(char **argv) 24 | { 25 | printf("Usage: %s [OPTIONS]\n", basename(argv[0])); 26 | printf("\t-s, --silent\tPrint test summary\n"); 27 | printf("\t-r, --run test\tRun specific test:\n"); 28 | printf("\t\t tracefs run libtracefs tests\n"); 29 | printf("\t-h, --help\tPrint usage information\n"); 30 | exit(0); 31 | } 32 | 33 | int main(int argc, char **argv) 34 | { 35 | CU_BasicRunMode verbose = CU_BRM_VERBOSE; 36 | enum unit_tests tests = RUN_NONE; 37 | 38 | for (;;) { 39 | int c; 40 | int index = 0; 41 | const char *opts = "+hsr:"; 42 | static struct option long_options[] = { 43 | {"silent", no_argument, NULL, 's'}, 44 | {"run", required_argument, NULL, 'r'}, 45 | {"help", no_argument, NULL, 'h'}, 46 | {NULL, 0, NULL, 0} 47 | }; 48 | 49 | c = getopt_long (argc, argv, opts, long_options, &index); 50 | if (c == -1) 51 | break; 52 | switch (c) { 53 | case 'r': 54 | if (strcmp(optarg, "tracefs") == 0) 55 | tests |= RUN_TRACEFS; 56 | else 57 | print_help(argv); 58 | break; 59 | case 's': 60 | verbose = CU_BRM_SILENT; 61 | break; 62 | case 'h': 63 | default: 64 | print_help(argv); 65 | break; 66 | } 67 | } 68 | 69 | if (tests == RUN_NONE) 70 | tests = RUN_ALL; 71 | 72 | if (CU_initialize_registry() != CUE_SUCCESS) { 73 | printf("Test registry cannot be initialized\n"); 74 | return -1; 75 | } 76 | 77 | if (tests & RUN_TRACEFS) 78 | test_tracefs_lib(); 79 | 80 | CU_basic_set_mode(verbose); 81 | CU_basic_run_tests(); 82 | CU_cleanup_registry(); 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /utest/trace-utest.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1 */ 2 | /* 3 | * Copyright (C) 2020, VMware, Tzvetomir Stoyanov 4 | * 5 | */ 6 | #ifndef _TRACE_UTEST_H_ 7 | #define _TRACE_UTEST_H_ 8 | 9 | void test_tracefs_lib(void); 10 | 11 | #endif /* _TRACE_UTEST_H_ */ 12 | --------------------------------------------------------------------------------