Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libtraceevent for openSUSE:Factory checked in at 2026-11-03 17:51:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libtraceevent (Old) and /work/SRC/openSUSE:Factory/.libtraceevent.new.1257 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libtraceevent" Tue Nov 3 17:51:19 2026 rev:18 rq:1394334 version:1.9.1 Changes: -------- --- /work/SRC/openSUSE:Factory/libtraceevent/libtraceevent.changes 2026-03-11 20:49:43.976181039 +0100 +++ /work/SRC/openSUSE:Factory/.libtraceevent.new.1257/libtraceevent.changes 2026-11-03 17:51:21.050750622 +0100 @@ -1,0 +2,15 @@ +Sun Nov 1 21:35:03 UTC 2026 - Dirk Müller <[email protected]> + +- update to 1.9.1: + * Fix leaks and NULL check in process_int_dynamic_array() + * Avoid host-specific getname_flags output + * Handle short reads when reading BTF + * Avoid racing recursive builds of both libraries + * Reject non-text symbol arithmetic + * Add printable characters + * Parse %pB and %pa address specifiers + * Pretty print function parameters of enum-type + * utest: Fix type of args in test_btf_read + * utest: Read btf file in utest if mmap fails + +------------------------------------------------------------------- Old: ---- libtraceevent-1.9.0.tar.gz New: ---- libtraceevent-1.9.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libtraceevent.spec ++++++ --- /var/tmp/diff_new_pack.aWLvxN/_old 2026-11-03 17:51:22.413807595 +0100 +++ /var/tmp/diff_new_pack.aWLvxN/_new 2026-11-03 17:51:22.416807721 +0100 @@ -22,7 +22,7 @@ %define sodname %{dname}%{sonum} Name: libtraceevent -Version: 1.9.0 +Version: 1.9.1 Release: 0 Summary: Linux kernel trace event library License: GPL-2.0-only AND LGPL-2.1-only ++++++ libtraceevent-1.9.0.tar.gz -> libtraceevent-1.9.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtraceevent-1.9.0/Makefile new/libtraceevent-1.9.1/Makefile --- old/libtraceevent-1.9.0/Makefile 2026-02-04 19:48:50.000000000 +0100 +++ new/libtraceevent-1.9.1/Makefile 2026-10-21 16:33:05.000000000 +0200 @@ -2,7 +2,7 @@ # libtraceevent version EP_VERSION = 1 EP_PATCHLEVEL = 9 -EP_EXTRAVERSION = 0 +EP_EXTRAVERSION = 1 EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) MAKEFLAGS += --no-print-directory @@ -208,7 +208,7 @@ libs: libtraceevent.a libtraceevent.so -$(LIBTRACEEVENT_STATIC): force +$(LIBTRACEEVENT_STATIC): force $(LIBTRACEEVENT_SHARED) $(Q)$(call descend,$(src)/src,$@) $(LIBTRACEEVENT_SHARED): force diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtraceevent-1.9.0/meson.build new/libtraceevent-1.9.1/meson.build --- old/libtraceevent-1.9.0/meson.build 2026-02-04 19:48:50.000000000 +0100 +++ new/libtraceevent-1.9.1/meson.build 2026-10-21 16:33:05.000000000 +0200 @@ -6,7 +6,7 @@ 'libtraceevent', ['c'], meson_version: '>= 0.58.0', license: 'LGPL-2.1', - version: '1.9.0', + version: '1.9.1', default_options: [ 'c_std=gnu99', 'buildtype=debug', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtraceevent-1.9.0/src/event-parse.c new/libtraceevent-1.9.1/src/event-parse.c --- old/libtraceevent-1.9.0/src/event-parse.c 2026-02-04 19:48:50.000000000 +0100 +++ new/libtraceevent-1.9.1/src/event-parse.c 2026-10-21 16:33:05.000000000 +0200 @@ -1017,6 +1017,19 @@ return ret; } +static bool is_kernel_text_symbol(char ch) +{ + switch (ch) { + case 'T': + case 't': + case 'W': + case 'w': + return true; + default: + return false; + } +} + /** * tep_parse_kallsyms - load functions from a read of /proc/kallsyms * @tep: a handle to the trace event parser @@ -1070,6 +1083,10 @@ * - x86-64 that reports per-cpu variable offsets as absolute */ if (func[0] != '$' && ch != 'A' && ch != 'a') { + if (!is_kernel_text_symbol(ch)) { + line = strtok_r(NULL, "\n", &next); + continue; + } line[func_end] = 0; if (mod_end) { mod = line + mod_start; @@ -3473,8 +3490,11 @@ * the index into where the array starts. */ type = read_token(event->tep, &token); - if (type != TEP_EVENT_ITEM) + if (type != TEP_EVENT_ITEM) { + free_token(token); + *tok = NULL; return TEP_EVENT_ERROR; + } /* Find the field */ field = tep_find_field(event, token); @@ -3490,7 +3510,7 @@ goto out; arg->int_array.field = alloc_arg(); - if (!arg) { + if (!arg->int_array.field) { do_warning_event(event, "%s: not enough memory!", __func__); goto out; } @@ -3499,6 +3519,7 @@ arg->int_array.field->dynarray.field = field; arg->int_array.field->dynarray.index = 0; + free_token(token); return read_token_item(event->tep, tok); out: free_token(token); @@ -4580,13 +4601,16 @@ } static unsigned long long test_for_symbol(struct tep_handle *tep, - struct tep_print_arg *arg) + struct tep_print_arg *arg, + bool *found) { unsigned long long val = 0; struct func_list *item = tep->funclist; char *func; int i; + *found = false; + if (isdigit(arg->atom.atom[0])) return 0; @@ -4607,10 +4631,14 @@ if (strcmp(arg->atom.atom, name) == 0) { val = addr; + *found = true; break; } } + if (!*found) + return 0; + /* * This modifies the arg to hardcode the value * and will not loop again. @@ -4686,13 +4714,17 @@ } static unsigned long long -eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg *arg) +eval_num_arg_stat(void *data, int size, struct tep_event *event, + struct tep_print_arg *arg, bool *valid) { struct tep_handle *tep = event->tep; unsigned long long val = 0; unsigned long long left, right; struct tep_print_arg *typearg = NULL; struct tep_print_arg *larg; + bool found = false; + bool left_valid = true; + bool right_valid = true; unsigned int offset; unsigned int field_size; @@ -4702,8 +4734,11 @@ return 0; case TEP_PRINT_ATOM: val = strtoull(arg->atom.atom, NULL, 0); - if (!val) - val = test_for_symbol(tep, arg); + if (!val && !isdigit(arg->atom.atom[0])) { + val = test_for_symbol(tep, arg, &found); + if (!found) + *valid = false; + } return val; case TEP_PRINT_FIELD: if (!arg->field.field) { @@ -4728,7 +4763,10 @@ case TEP_PRINT_HEX_STR: break; case TEP_PRINT_TYPE: - val = eval_num_arg(data, size, event, arg->typecast.item); + val = eval_num_arg_stat(data, size, event, arg->typecast.item, + valid); + if (!*valid) + return 0; return eval_type(val, arg, 0); case TEP_PRINT_STRING: case TEP_PRINT_BSTRING: @@ -4749,7 +4787,12 @@ * Arrays are special, since we don't want * to read the arg as is. */ - right = eval_num_arg(data, size, event, arg->op.right); + right = eval_num_arg_stat(data, size, event, + arg->op.right, &right_valid); + if (!right_valid) { + *valid = false; + return 0; + } /* handle typecasts */ larg = arg->op.left; @@ -4797,17 +4840,34 @@ val = eval_type(val, typearg, 1); break; } else if (strcmp(arg->op.op, "?") == 0) { - left = eval_num_arg(data, size, event, arg->op.left); + left = eval_num_arg_stat(data, size, event, arg->op.left, + &left_valid); + if (!left_valid) { + *valid = false; + return 0; + } arg = arg->op.right; if (left) - val = eval_num_arg(data, size, event, arg->op.left); + val = eval_num_arg_stat(data, size, event, + arg->op.left, &left_valid); else - val = eval_num_arg(data, size, event, arg->op.right); + val = eval_num_arg_stat(data, size, event, + arg->op.right, &right_valid); + if ((left && !left_valid) || (!left && !right_valid)) { + *valid = false; + return 0; + } break; } default_op: - left = eval_num_arg(data, size, event, arg->op.left); - right = eval_num_arg(data, size, event, arg->op.right); + left = eval_num_arg_stat(data, size, event, arg->op.left, + &left_valid); + right = eval_num_arg_stat(data, size, event, arg->op.right, + &right_valid); + if (!left_valid || !right_valid) { + *valid = false; + return 0; + } switch (arg->op.op[0]) { case '!': switch (arg->op.op[1]) { @@ -4922,6 +4982,15 @@ return 0; } +static unsigned long long +eval_num_arg(void *data, int size, struct tep_event *event, + struct tep_print_arg *arg) +{ + bool valid = true; + + return eval_num_arg_stat(data, size, event, arg, &valid); +} + struct flag { const char *name; unsigned long long value; @@ -5350,6 +5419,7 @@ case TEP_PRINT_INT_ARRAY: { void *num; int el_size; + int is_print = 0; len = 0; @@ -5384,7 +5454,20 @@ trace_seq_putc(s, ','); if (el_size == 1) { - trace_seq_printf(s, "0x%x", *(uint8_t *)num); + int ch = *(uint8_t *)num; + + trace_seq_printf(s, "0x%x", ch); + + if (!is_print) + is_print = 1; + + /* + * Only print string if all characters are + * printable + */ + if (is_print && !isprint(ch) && !isspace(ch)) + is_print = -1; + } else if (el_size == 2) { trace_seq_printf(s, "0x%x", *(uint16_t *)num); } else if (el_size == 4) { @@ -5400,6 +5483,19 @@ num += el_size; } trace_seq_putc(s, '}'); + + if (is_print == 1) { + char *p = data + offset; + + trace_seq_puts(s, " \""); + for (i = 0; i < len; i++) { + if (p[i] == '\n') + trace_seq_puts(s, "\\n"); + else + trace_seq_putc(s, p[i]); + } + trace_seq_putc(s, '"'); + } break; } case TEP_PRINT_TYPE: @@ -6607,9 +6703,14 @@ struct tep_print_arg *arg, bool raw) { struct func_map *func; + bool valid = true; unsigned long long val; - val = eval_num_arg(data, size, event, arg); + val = eval_num_arg_stat(data, size, event, arg, &valid); + if (!valid) { + trace_seq_puts(s, "INVALID"); + return 0; + } func = find_func(event->tep, val); if (func) { trace_seq_puts(s, func->func); @@ -6631,11 +6732,84 @@ return 0; } +static int print_function_backtrace(struct trace_seq *s, + void *data, int size, + struct tep_event *event, + struct tep_print_arg *arg, bool raw) +{ + struct func_map *func = NULL; + unsigned long long lookup; + unsigned long long val; + + val = eval_num_arg(data, size, event, arg); + lookup = val ? val - 1 : 0; + func = val ? find_func(event->tep, lookup) : NULL; + + if (func) { + trace_seq_puts(s, func->func); + trace_seq_printf(s, "+0x%llx", lookup - func->addr); + } + + if (!func || raw) { + if (raw) + trace_seq_puts(s, " ("); + if (event->tep->long_size == 4) + trace_seq_printf(s, "0x%lx", (long)val); + else + trace_seq_printf(s, "0x%llx", (long long)val); + if (raw) + trace_seq_puts(s, ")"); + } + + return 0; +} + +static int print_addr_ref_arg(struct trace_seq *s, const char *format, + void *data, int size, + struct tep_event *event, + struct tep_print_arg *arg) +{ + struct tep_format_field *field; + struct tep_handle *tep = event->tep; + unsigned long long val; + int width; + int ret = 0; + + while (arg->type == TEP_PRINT_TYPE) + arg = arg->typecast.item; + + if (arg->type != TEP_PRINT_FIELD) { + trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type); + return ret; + } + + field = arg->field.field; + if (!field) { + field = tep_find_any_field(event, arg->field.name); + if (!field) { + do_warning_event(event, "%s: field %s not found", + __func__, arg->field.name); + return ret; + } + arg->field.field = field; + } + + val = tep_read_number(tep, data + field->offset, field->size); + width = field->size * 2; + trace_seq_printf(s, "0x%0*llx", width, val); + + if (format[1] == 'p' || format[1] == 'd') + ret++; + + return ret; +} + static int print_arg_pointer(struct trace_seq *s, const char *format, int plen, void *data, int size, struct tep_event *event, struct tep_print_arg *arg, bool raw) { + bool valid = true; unsigned long long val; int ret = 1; @@ -6652,12 +6826,18 @@ } switch (*format) { + case 'B': + ret += print_function_backtrace(s, data, size, event, arg, raw); + break; case 'F': case 'f': case 'S': case 's': ret += print_function(s, format, data, size, event, arg, raw); break; + case 'a': + ret += print_addr_ref_arg(s, format, data, size, event, arg); + break; case 'M': case 'm': ret += print_mac_arg(s, format, data, size, event, arg); @@ -6674,7 +6854,11 @@ break; default: ret = 0; - val = eval_num_arg(data, size, event, arg); + val = eval_num_arg_stat(data, size, event, arg, &valid); + if (!valid) { + trace_seq_puts(s, "INVALID"); + break; + } trace_seq_printf(s, "%p", (void *)(intptr_t)val); break; } @@ -6687,9 +6871,14 @@ void *data, int size, int ls, struct tep_event *event, struct tep_print_arg *arg) { + bool valid = true; unsigned long long val; - val = eval_num_arg(data, size, event, arg); + val = eval_num_arg_stat(data, size, event, arg, &valid); + if (!valid) { + trace_seq_puts(s, "INVALID"); + return 0; + } switch (ls) { case -2: @@ -6752,12 +6941,24 @@ int loop; switch (*format) { + case 'B': + ret++; + break; case 'F': case 'S': case 'f': case 's': ret++; break; + case 'a': + switch (format[1]) { + case 'p': + case 'd': + ret++; + break; + } + ret++; + break; case 'M': case 'm': /* [mM]R , [mM]F */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtraceevent-1.9.0/src/kbuffer-parse.c new/libtraceevent-1.9.1/src/kbuffer-parse.c --- old/libtraceevent-1.9.0/src/kbuffer-parse.c 2026-02-04 19:48:50.000000000 +0100 +++ new/libtraceevent-1.9.1/src/kbuffer-parse.c 2026-10-21 16:33:05.000000000 +0200 @@ -849,7 +849,7 @@ int kbuffer_missed_events(struct kbuffer *kbuf) { /* Only the first event can have missed events */ - if (kbuf->curr) + if (kbuf->curr != kbuf->first) return 0; return kbuf->lost_events; @@ -1014,7 +1014,7 @@ * If reading the first event and there are lost events, add it * to the buffer. */ - if (!save_curr && kbuf->lost_events) { + if (save_curr == kbuf->first && kbuf->lost_events) { unsigned long long cnt_8; unsigned int cnt_4; int word_size; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtraceevent-1.9.0/src/trace-btf.c new/libtraceevent-1.9.1/src/trace-btf.c --- old/libtraceevent-1.9.0/src/trace-btf.c 2026-02-04 19:48:50.000000000 +0100 +++ new/libtraceevent-1.9.1/src/trace-btf.c 2026-10-21 16:33:05.000000000 +0200 @@ -32,6 +32,16 @@ #define REALLOC_SIZE (1 << 10) #define REALLOC_MASK (REALLOC_SIZE - 1) +#define for_each_enum(enum_type, member) \ + member = btf_enum(enum_type); \ + for (int __i = 0; __i < BTF_INFO_VLEN((enum_type)->info); \ + __i++, member++) + +static inline struct btf_enum *btf_enum(struct btf_type *t) +{ + return (struct btf_enum *)(t + 1); +} + static const char *btf_name(struct tep_btf *btf, int off) { if (off < btf->hdr->str_len) @@ -546,6 +556,7 @@ struct tep_btf *btf = tep->btf; struct btf_type *type = tep_btf_find_func(btf, func); struct btf_param *param; + struct btf_enum *enump; unsigned long long arg; unsigned int encode; const char *param_name; @@ -628,6 +639,13 @@ break; case BTF_KIND_ENUM: trace_seq_printf(s, "%lld", arg); + for_each_enum(t, enump) { + if (arg == enump->val) { + trace_seq_printf(s, " [%s]", + btf_name(btf, enump->name_off)); + break; + } + } break; default: /* This does not handle complex arguments */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libtraceevent-1.9.0/utest/traceevent-utest.c new/libtraceevent-1.9.1/utest/traceevent-utest.c --- old/libtraceevent-1.9.0/utest/traceevent-utest.c 2026-02-04 19:48:50.000000000 +0100 +++ new/libtraceevent-1.9.1/utest/traceevent-utest.c 2026-10-21 16:33:05.000000000 +0200 @@ -8,14 +8,18 @@ */ #include <stdio.h> #include <stdlib.h> +#include <stdint.h> +#include <errno.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <time.h> #include <dirent.h> #include <ftw.h> +#include <string.h> #include <sys/mman.h> +#include <stdint.h> #include <CUnit/CUnit.h> #include <CUnit/Basic.h> @@ -182,6 +186,126 @@ }; static void *sizeof_event_data = (void *)sizeof_data; +static const char symbol_kallsyms[] = + "0000000000001000 T _stext\n" + "0000000000001020 T do_work\n" + "0000000000001100 T end_text\n" + "0000000000002000 D jiffies\n"; + +#define SYMBOL_ARITH_FMT "caller=do_work+0x0" +static const char symbol_arith_event[] = + "name: symbol_arith\n" + "ID: 24\n" + "format:\n" + "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n" + "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n" + "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n" + "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n" + "\n" + "\tfield:unsigned int caller_off;\toffset:8;\tsize:4;\tsigned:0;\n" + "\n" + "print fmt: \"caller=%pS\", REC->caller_off + _stext\n"; + +static char symbol_arith_data[] = { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + /* common type */ 24, 0x00, +#else + /* common type */ 0x00, 24, +#endif + /* common flags */ 0x00, + /* common_preempt_count */ 0x00, + /* common_pid */ 0x00, 0x00, 0x00, 0x00, +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + /* caller_off */ 0x20, 0x00, 0x00, 0x00, +#else + /* caller_off */ 0x00, 0x00, 0x00, 0x20, +#endif +}; + +#define JIFFIES_ARITH_FMT "age=INVALID" +static const char jiffies_arith_event[] = + "name: jiffies_arith\n" + "ID: 25\n" + "format:\n" + "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n" + "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n" + "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n" + "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n" + "\n" + "\tfield:unsigned long dirtied_when;\toffset:8;\tsize:8;\tsigned:0;\n" + "\n" + "print fmt: \"age=%lu\", (jiffies - REC->dirtied_when) / 250\n"; + +static char jiffies_arith_data[] = { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + /* common type */ 25, 0x00, +#else + /* common type */ 0x00, 25, +#endif + /* common flags */ 0x00, + /* common_preempt_count */ 0x00, + /* common_pid */ 0x00, 0x00, 0x00, 0x00, +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + /* dirtied_when */ 0xf4, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +#else + /* dirtied_when */ 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xf4, +#endif +}; + +static const char pointer_backtrace_event[] = + "name: pointer_backtrace_event\n" + "ID: 40\n" + "format:\n" + "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n" + "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n" + "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n" + "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n" + "\n" + "\tfield:unsigned long long ptr;\toffset:8;\tsize:8;\tsigned:0;\n" + "\n" + "print fmt: \"ptr=%pB\", REC->ptr\n"; + +static const char phys_addr_event[] = + "name: phys_addr_event\n" + "ID: 41\n" + "format:\n" + "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n" + "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n" + "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n" + "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n" + "\n" + "\tfield:unsigned long long phys;\toffset:8;\tsize:8;\tsigned:0;\n" + "\n" + "print fmt: \"phys=%pap\", REC->phys\n"; + +static const char phys_addr_plain_event[] = + "name: phys_addr_plain_event\n" + "ID: 43\n" + "format:\n" + "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n" + "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n" + "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n" + "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n" + "\n" + "\tfield:unsigned long long phys;\toffset:8;\tsize:8;\tsigned:0;\n" + "\n" + "print fmt: \"phys=%pa\", REC->phys\n"; + +static const char dma_addr_event[] = + "name: dma_addr_event\n" + "ID: 42\n" + "format:\n" + "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n" + "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n" + "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n" + "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n" + "\n" + "\tfield:unsigned int dma;\toffset:8;\tsize:4;\tsigned:0;\n" + "\n" + "print fmt: \"dma=%pad\", REC->dma\n"; + DECL_CPUMASK_EVENT_DATA(full, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); #define CPUMASK_FULL "ARRAY[ff, ff, ff, ff, ff, ff, ff, ff]" #define CPUMASK_FULL_FMT "cpumask=0-63" @@ -380,14 +504,165 @@ test_parse_sizeof(0, 5, "sizeof_undef", SIZEOF_LONG0_FMT); } +static void parse_symbol_event(const char *format, const char *system, + void *data, int size, const char *expected) +{ + struct tep_handle *tep; + struct tep_event *event; + struct tep_record record; + + tep = tep_alloc(); + CU_TEST(tep != NULL); + if (!tep) + return; + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + tep_set_file_bigendian(tep, TEP_BIG_ENDIAN); +#endif + + record.data = data; + record.size = size; + + CU_TEST(tep_parse_kallsyms(tep, symbol_kallsyms) == 0); + CU_TEST(tep_parse_format(tep, &event, format, strlen(format), + system) == TEP_ERRNO__SUCCESS); + + trace_seq_reset(test_seq); + tep_print_event(tep, test_seq, &record, "%s", TEP_PRINT_INFO); + trace_seq_do_printf(test_seq); + CU_TEST(strcmp(test_seq->buffer, expected) == 0); + + tep_free(tep); +} + +static void test_parse_symbol_arith(void) +{ + parse_symbol_event(symbol_arith_event, "symbol_arith", + symbol_arith_data, sizeof(symbol_arith_data), + SYMBOL_ARITH_FMT); +} + +static void test_parse_jiffies_arith(void) +{ + parse_symbol_event(jiffies_arith_event, "jiffies_arith", + jiffies_arith_data, sizeof(jiffies_arith_data), + JIFFIES_ARITH_FMT); +} + +static void parse_pointer_event(const char *format, const char *system, + void *data, int size, const char *expected) +{ + struct tep_event *event; + struct tep_record record; + + record.data = data; + record.size = size; + + CU_TEST(tep_parse_format(test_tep, &event, format, strlen(format), + system) == TEP_ERRNO__SUCCESS); + + trace_seq_reset(test_seq); + tep_print_event(test_tep, test_seq, &record, "%s", TEP_PRINT_INFO); + trace_seq_do_printf(test_seq); + CU_TEST(strcmp(test_seq->buffer, expected) == 0); +} + +static void test_parse_pointer_backtrace(void) +{ + unsigned char data[16] = { 0 }; + unsigned short type = 40; + uint64_t ptr = 0x1001ULL; + + memcpy(data, &type, sizeof(type)); + memcpy(data + 8, &ptr, sizeof(ptr)); + + parse_pointer_event(pointer_backtrace_event, "ptr_backtrace", + data, sizeof(data), "ptr=test_func+0x0"); +} + +static void test_parse_phys_addr(void) +{ + unsigned char data[16] = { 0 }; + unsigned short type = 41; + uint64_t phys = 0x123456789abcdef0ULL; + + memcpy(data, &type, sizeof(type)); + memcpy(data + 8, &phys, sizeof(phys)); + + parse_pointer_event(phys_addr_event, "ptr_phys", + data, sizeof(data), + "phys=0x123456789abcdef0"); +} + +static void test_parse_phys_addr_plain(void) +{ + unsigned char data[16] = { 0 }; + unsigned short type = 43; + uint64_t phys = 0x123456789abcdef0ULL; + + memcpy(data, &type, sizeof(type)); + memcpy(data + 8, &phys, sizeof(phys)); + + parse_pointer_event(phys_addr_plain_event, "ptr_phys_plain", + data, sizeof(data), + "phys=0x123456789abcdef0"); +} + +static void test_parse_dma_addr(void) +{ + unsigned char data[12] = { 0 }; + unsigned short type = 42; + uint32_t dma = 0x1234abcdU; + + memcpy(data, &type, sizeof(type)); + memcpy(data + 8, &dma, sizeof(dma)); + + parse_pointer_event(dma_addr_event, "ptr_dma", + data, sizeof(data), "dma=0x1234abcd"); +} + +static int read_full(int fd, void *buf, size_t size) +{ + char *data = buf; + size_t total = 0; + + while (total < size) { + ssize_t ret; + + ret = read(fd, data + total, size - total); + if (ret < 0) { + if (errno == EINTR) + continue; + return -1; + } + if (!ret) + return -1; + total += ret; + } + + return 0; +} + +static bool output_has_extra_args(const char *output, const char *prefix) +{ + size_t len = strlen(output); + size_t plen = strlen(prefix); + + return len > plen + 3 && strncmp(output, prefix, plen) == 0 && + output[plen] == ',' && strcmp(output + len - 2, ")\n") == 0; +} + static void test_btf_read(void) { - unsigned long args[] = {0x7ffe7d33f3d0, 0, 0, 0, 0, 0}; + uint64_t args[] = {0x7ffe7d33f3d0, 0, 0, 0, 0, 0}; const char *func = "getname_flags"; + const char *expected = "getname_flags(filename=0x7ffe7d33f3d0, flags=0)\n"; + const char *expected_prefix = "getname_flags(filename=0x7ffe7d33f3d0, flags=0"; struct trace_seq *s = test_seq; struct stat st; void *buf; int fd, nr = 6; + bool malloced = false; fd = open("/sys/kernel/btf/vmlinux", O_RDONLY); if (fd < 0) { @@ -397,22 +672,47 @@ CU_TEST(fstat(fd, &st) == 0); buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - CU_TEST(buf != MAP_FAILED); + if (buf == MAP_FAILED) { + int ret; + malloced = true; + buf = malloc(st.st_size); + if (buf == NULL) { + printf("[FAILED TO ALLOCATE MEMORY FOR BTF FILE CONTENTS] ..."); + close(fd); + return; + } + CU_TEST((ret = read_full(fd, buf, st.st_size)) == 0); + if (ret < 0) { + free(buf); + close(fd); + return; + } + } CU_TEST(tep_load_btf(test_tep, buf, st.st_size) == 0); - munmap(buf, st.st_size); + if (malloced) { + free(buf); + } else { + munmap(buf, st.st_size); + } close(fd); trace_seq_init(s); trace_seq_printf(s, "%s(", func); - CU_TEST(tep_btf_print_args(test_tep, s, args, nr, sizeof(long), func) == 0); + CU_TEST(tep_btf_print_args(test_tep, s, args, nr, sizeof(*args), func) == 0); trace_seq_puts(s, ")\n"); trace_seq_terminate(s); - CU_TEST(strcmp(s->buffer, "getname_flags(filename=0x7ffe7d33f3d0, flags=0)\n") == 0); + if (strcmp(s->buffer, expected) != 0 && + output_has_extra_args(s->buffer, expected_prefix)) { + printf("[KERNEL BTF HAS EXTRA getname_flags ARGS] ..."); + return; + } + + CU_TEST(strcmp(s->buffer, expected) == 0); } static int test_suite_destroy(void) @@ -429,6 +729,10 @@ test_tep = tep_alloc(); if (!test_tep) return 1; + if (tep_register_function(test_tep, "test_func", 0x1000, NULL)) + return 1; + if (tep_register_function(test_tep, "test_func_end", 0x2000, NULL)) + return 1; #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ tep_set_file_bigendian(test_tep, TEP_BIG_ENDIAN); #endif @@ -466,6 +770,18 @@ test_parse_sizeof4); CU_add_test(suite, "parse sizeof() no long size defined", test_parse_sizeof_undef); + CU_add_test(suite, "parse symbol arithmetic", + test_parse_symbol_arith); + CU_add_test(suite, "reject non-text symbol arithmetic", + test_parse_jiffies_arith); + CU_add_test(suite, "parse %pB pointer format", + test_parse_pointer_backtrace); + CU_add_test(suite, "parse %pap pointer format", + test_parse_phys_addr); + CU_add_test(suite, "parse %pa pointer format", + test_parse_phys_addr_plain); + CU_add_test(suite, "parse %pad pointer format", + test_parse_dma_addr); CU_add_test(suite, "read BTF", test_btf_read); }
