Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tools lib traceevent: Separate out tep_strerror() for strerror_r() issues

While working on having PowerTop use libtracevent as a shared object
library, Tzvetomir hit "str_error_r not defined". This was added by commit
c3cec9e68f12d ("tools lib traceevent: Use str_error_r()") because
strerror_r() has two definitions, where one is GNU specific, and the other
is XSI complient. The strerror_r() is in a wrapper str_error_r() to keep the
code from having to worry about which compiler is being used.

The problem is that str_error_r() is external to libtraceevent, and not part
of the library. If it is used as a shared object then the tools using it
will need to define that function. I do not want that function defined in
libtraceevent itself, as it is out of scope for that library.

As there's only a single instance of this call, and its in the traceevent
library's own tep_strerror() function, we can copy what was done in perf,
and create yet another external file that undefs _GNU_SOURCE to use the more
portable version of the function. We don't need to worry about the errors
that strerror_r() returns. If the buffer isn't big enough, we simply
truncate it.

Reported-by: Tzvetomir Stoyanov <tstoyanov@vmware.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com>
Cc: linux trace devel <linux-trace-devel@vger.kernel.org>
Link: http://lkml.kernel.org/r/20181005121816.484e654f@gandalf.local.home
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Steven Rostedt (VMware) and committed by
Arnaldo Carvalho de Melo
bbbab191 8b2f245f

+54 -30
+1
tools/lib/traceevent/Build
··· 4 4 libtraceevent-y += parse-filter.o 5 5 libtraceevent-y += parse-utils.o 6 6 libtraceevent-y += kbuffer-parse.o 7 + libtraceevent-y += tep_strerror.o 7 8 8 9 plugin_jbd2-y += plugin_jbd2.o 9 10 plugin_hrtimer-y += plugin_hrtimer.o
-30
tools/lib/traceevent/event-parse.c
··· 18 18 #include <errno.h> 19 19 #include <stdint.h> 20 20 #include <limits.h> 21 - #include <linux/string.h> 22 21 #include <linux/time64.h> 23 22 24 23 #include <netinet/in.h> ··· 6198 6199 { 6199 6200 struct tep_event_format *event = NULL; 6200 6201 return __parse_event(pevent, &event, buf, size, sys); 6201 - } 6202 - 6203 - #undef _PE 6204 - #define _PE(code, str) str 6205 - static const char * const tep_error_str[] = { 6206 - TEP_ERRORS 6207 - }; 6208 - #undef _PE 6209 - 6210 - int tep_strerror(struct tep_handle *pevent __maybe_unused, 6211 - enum tep_errno errnum, char *buf, size_t buflen) 6212 - { 6213 - int idx; 6214 - const char *msg; 6215 - 6216 - if (errnum >= 0) { 6217 - str_error_r(errnum, buf, buflen); 6218 - return 0; 6219 - } 6220 - 6221 - if (errnum <= __TEP_ERRNO__START || 6222 - errnum >= __TEP_ERRNO__END) 6223 - return -1; 6224 - 6225 - idx = errnum - __TEP_ERRNO__START - 1; 6226 - msg = tep_error_str[idx]; 6227 - snprintf(buf, buflen, "%s", msg); 6228 - 6229 - return 0; 6230 6202 } 6231 6203 6232 6204 int get_field_val(struct trace_seq *s, struct tep_format_field *field,
+53
tools/lib/traceevent/tep_strerror.c
··· 1 + // SPDX-License-Identifier: LGPL-2.1 2 + #undef _GNU_SOURCE 3 + #include <string.h> 4 + #include <stdio.h> 5 + 6 + #include "event-parse.h" 7 + 8 + #undef _PE 9 + #define _PE(code, str) str 10 + static const char * const tep_error_str[] = { 11 + TEP_ERRORS 12 + }; 13 + #undef _PE 14 + 15 + /* 16 + * The tools so far have been using the strerror_r() GNU variant, that returns 17 + * a string, be it the buffer passed or something else. 18 + * 19 + * But that, besides being tricky in cases where we expect that the function 20 + * using strerror_r() returns the error formatted in a provided buffer (we have 21 + * to check if it returned something else and copy that instead), breaks the 22 + * build on systems not using glibc, like Alpine Linux, where musl libc is 23 + * used. 24 + * 25 + * So, introduce yet another wrapper, str_error_r(), that has the GNU 26 + * interface, but uses the portable XSI variant of strerror_r(), so that users 27 + * rest asured that the provided buffer is used and it is what is returned. 28 + */ 29 + int tep_strerror(struct tep_handle *tep __maybe_unused, 30 + enum tep_errno errnum, char *buf, size_t buflen) 31 + { 32 + const char *msg; 33 + int idx; 34 + 35 + if (!buflen) 36 + return 0; 37 + 38 + if (errnum >= 0) { 39 + int err = strerror_r(errnum, buf, buflen); 40 + buf[buflen - 1] = 0; 41 + return err; 42 + } 43 + 44 + if (errnum <= __TEP_ERRNO__START || 45 + errnum >= __TEP_ERRNO__END) 46 + return -1; 47 + 48 + idx = errnum - __TEP_ERRNO__START - 1; 49 + msg = tep_error_str[idx]; 50 + snprintf(buf, buflen, "%s", msg); 51 + 52 + return 0; 53 + }