forked from Minki/linux
tools lib traceevent: Optimize pretty_print() function
Each time the pretty_print() function is called to print an event, the event's format string is parsed. As this format string does not change, this parsing can be done only once - when the event struct is initialized. Link: https://lore.kernel.org/linux-trace-devel/20200529134929.537110-1-tz.stoyanov@gmail.com Link: http://lore.kernel.org/linux-trace-devel/20200625100516.365338-8-tz.stoyanov@gmail.com Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: linux-trace-devel@vger.kernel.org Link: http://lore.kernel.org/lkml/20200702185704.559785000@goodmis.org Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
487ae1f4a1
commit
e7a90882b0
@ -85,6 +85,23 @@ struct tep_handle {
|
||||
struct tep_plugins_dir *plugins_dir;
|
||||
};
|
||||
|
||||
enum tep_print_parse_type {
|
||||
PRINT_FMT_STING,
|
||||
PRINT_FMT_ARG_DIGIT,
|
||||
PRINT_FMT_ARG_POINTER,
|
||||
PRINT_FMT_ARG_STRING,
|
||||
};
|
||||
|
||||
struct tep_print_parse {
|
||||
struct tep_print_parse *next;
|
||||
|
||||
char *format;
|
||||
int ls;
|
||||
enum tep_print_parse_type type;
|
||||
struct tep_print_arg *arg;
|
||||
struct tep_print_arg *len_as_arg;
|
||||
};
|
||||
|
||||
void tep_free_event(struct tep_event *event);
|
||||
void tep_free_format_field(struct tep_format_field *field);
|
||||
void tep_free_plugin_paths(struct tep_handle *tep);
|
||||
|
@ -5215,13 +5215,25 @@ static int print_function(struct trace_seq *s, const char *format,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_pointer(struct trace_seq *s, const char *format, int plen,
|
||||
void *data, int size,
|
||||
struct tep_event *event, struct tep_print_arg *arg)
|
||||
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)
|
||||
{
|
||||
unsigned long long val;
|
||||
int ret = 1;
|
||||
|
||||
if (arg->type == TEP_PRINT_BSTRING) {
|
||||
trace_seq_puts(s, arg->string.string);
|
||||
return 0;
|
||||
}
|
||||
while (*format) {
|
||||
if (*format == 'p') {
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
switch (*format) {
|
||||
case 'F':
|
||||
case 'f':
|
||||
@ -5254,23 +5266,476 @@ static int print_pointer(struct trace_seq *s, const char *format, int plen,
|
||||
|
||||
}
|
||||
|
||||
static int print_arg_number(struct trace_seq *s, const char *format, int plen,
|
||||
void *data, int size, int ls,
|
||||
struct tep_event *event, struct tep_print_arg *arg)
|
||||
{
|
||||
unsigned long long val;
|
||||
|
||||
val = eval_num_arg(data, size, event, arg);
|
||||
|
||||
switch (ls) {
|
||||
case -2:
|
||||
if (plen >= 0)
|
||||
trace_seq_printf(s, format, plen, (char)val);
|
||||
else
|
||||
trace_seq_printf(s, format, (char)val);
|
||||
break;
|
||||
case -1:
|
||||
if (plen >= 0)
|
||||
trace_seq_printf(s, format, plen, (short)val);
|
||||
else
|
||||
trace_seq_printf(s, format, (short)val);
|
||||
break;
|
||||
case 0:
|
||||
if (plen >= 0)
|
||||
trace_seq_printf(s, format, plen, (int)val);
|
||||
else
|
||||
trace_seq_printf(s, format, (int)val);
|
||||
break;
|
||||
case 1:
|
||||
if (plen >= 0)
|
||||
trace_seq_printf(s, format, plen, (long)val);
|
||||
else
|
||||
trace_seq_printf(s, format, (long)val);
|
||||
break;
|
||||
case 2:
|
||||
if (plen >= 0)
|
||||
trace_seq_printf(s, format, plen, (long long)val);
|
||||
else
|
||||
trace_seq_printf(s, format, (long long)val);
|
||||
break;
|
||||
default:
|
||||
do_warning_event(event, "bad count (%d)", ls);
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void print_arg_string(struct trace_seq *s, const char *format, int plen,
|
||||
void *data, int size,
|
||||
struct tep_event *event, struct tep_print_arg *arg)
|
||||
{
|
||||
struct trace_seq p;
|
||||
|
||||
/* Use helper trace_seq */
|
||||
trace_seq_init(&p);
|
||||
print_str_arg(&p, data, size, event,
|
||||
format, plen, arg);
|
||||
trace_seq_terminate(&p);
|
||||
trace_seq_puts(s, p.buffer);
|
||||
trace_seq_destroy(&p);
|
||||
}
|
||||
|
||||
static int parse_arg_format_pointer(const char *format)
|
||||
{
|
||||
int ret = 0;
|
||||
int index;
|
||||
int loop;
|
||||
|
||||
switch (*format) {
|
||||
case 'F':
|
||||
case 'S':
|
||||
case 'f':
|
||||
case 's':
|
||||
ret++;
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
/* [mM]R , [mM]F */
|
||||
switch (format[1]) {
|
||||
case 'R':
|
||||
case 'F':
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
ret++;
|
||||
break;
|
||||
case 'I':
|
||||
case 'i':
|
||||
index = 2;
|
||||
loop = 1;
|
||||
switch (format[1]) {
|
||||
case 'S':
|
||||
/*[S][pfs]*/
|
||||
while (loop) {
|
||||
switch (format[index]) {
|
||||
case 'p':
|
||||
case 'f':
|
||||
case 's':
|
||||
ret++;
|
||||
index++;
|
||||
break;
|
||||
default:
|
||||
loop = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
case '4':
|
||||
/* [4S][hnbl] */
|
||||
switch (format[index]) {
|
||||
case 'h':
|
||||
case 'n':
|
||||
case 'l':
|
||||
case 'b':
|
||||
ret++;
|
||||
index++;
|
||||
break;
|
||||
}
|
||||
if (format[1] == '4') {
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case '6':
|
||||
/* [6S]c */
|
||||
if (format[index] == 'c')
|
||||
ret++;
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
ret++;
|
||||
break;
|
||||
case 'U':
|
||||
switch (format[1]) {
|
||||
case 'L':
|
||||
case 'l':
|
||||
case 'B':
|
||||
case 'b':
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
ret++;
|
||||
break;
|
||||
case 'h':
|
||||
switch (format[1]) {
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'N':
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
ret++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void free_parse_args(struct tep_print_parse *arg)
|
||||
{
|
||||
struct tep_print_parse *del;
|
||||
|
||||
while (arg) {
|
||||
del = arg;
|
||||
arg = del->next;
|
||||
free(del->format);
|
||||
free(del);
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_arg_add(struct tep_print_parse **parse, char *format,
|
||||
enum tep_print_parse_type type,
|
||||
struct tep_print_arg *arg,
|
||||
struct tep_print_arg *len_as_arg,
|
||||
int ls)
|
||||
{
|
||||
struct tep_print_parse *parg = NULL;
|
||||
|
||||
parg = calloc(1, sizeof(*parg));
|
||||
if (!parg)
|
||||
goto error;
|
||||
parg->format = strdup(format);
|
||||
if (!parg->format)
|
||||
goto error;
|
||||
parg->type = type;
|
||||
parg->arg = arg;
|
||||
parg->len_as_arg = len_as_arg;
|
||||
parg->ls = ls;
|
||||
*parse = parg;
|
||||
return 0;
|
||||
error:
|
||||
if (parg) {
|
||||
free(parg->format);
|
||||
free(parg);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_arg_format(struct tep_print_parse **parse,
|
||||
struct tep_event *event,
|
||||
const char *format, struct tep_print_arg **arg)
|
||||
{
|
||||
struct tep_print_arg *len_arg = NULL;
|
||||
char print_format[32];
|
||||
const char *start = format;
|
||||
int ret = 0;
|
||||
int ls = 0;
|
||||
int res;
|
||||
int len;
|
||||
|
||||
format++;
|
||||
ret++;
|
||||
for (; *format; format++) {
|
||||
switch (*format) {
|
||||
case '#':
|
||||
/* FIXME: need to handle properly */
|
||||
break;
|
||||
case 'h':
|
||||
ls--;
|
||||
break;
|
||||
case 'l':
|
||||
ls++;
|
||||
break;
|
||||
case 'L':
|
||||
ls = 2;
|
||||
break;
|
||||
case '.':
|
||||
case 'z':
|
||||
case 'Z':
|
||||
case '0' ... '9':
|
||||
case '-':
|
||||
break;
|
||||
case '*':
|
||||
/* The argument is the length. */
|
||||
if (!*arg) {
|
||||
do_warning_event(event, "no argument match");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
goto out_failed;
|
||||
}
|
||||
if (len_arg) {
|
||||
do_warning_event(event, "argument already matched");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
goto out_failed;
|
||||
}
|
||||
len_arg = *arg;
|
||||
*arg = (*arg)->next;
|
||||
break;
|
||||
case 'p':
|
||||
if (!*arg) {
|
||||
do_warning_event(event, "no argument match");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
goto out_failed;
|
||||
}
|
||||
res = parse_arg_format_pointer(format + 1);
|
||||
if (res > 0) {
|
||||
format += res;
|
||||
ret += res;
|
||||
}
|
||||
len = ((unsigned long)format + 1) -
|
||||
(unsigned long)start;
|
||||
/* should never happen */
|
||||
if (len > 31) {
|
||||
do_warning_event(event, "bad format!");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
len = 31;
|
||||
}
|
||||
memcpy(print_format, start, len);
|
||||
print_format[len] = 0;
|
||||
|
||||
parse_arg_add(parse, print_format,
|
||||
PRINT_FMT_ARG_POINTER, *arg, len_arg, ls);
|
||||
*arg = (*arg)->next;
|
||||
ret++;
|
||||
return ret;
|
||||
case 'd':
|
||||
case 'u':
|
||||
case 'i':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'o':
|
||||
if (!*arg) {
|
||||
do_warning_event(event, "no argument match");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
goto out_failed;
|
||||
}
|
||||
|
||||
len = ((unsigned long)format + 1) -
|
||||
(unsigned long)start;
|
||||
|
||||
/* should never happen */
|
||||
if (len > 30) {
|
||||
do_warning_event(event, "bad format!");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
len = 31;
|
||||
}
|
||||
memcpy(print_format, start, len);
|
||||
print_format[len] = 0;
|
||||
|
||||
if (event->tep->long_size == 8 && ls == 1 &&
|
||||
sizeof(long) != 8) {
|
||||
char *p;
|
||||
|
||||
/* make %l into %ll */
|
||||
if (ls == 1 && (p = strchr(print_format, 'l')))
|
||||
memmove(p+1, p, strlen(p)+1);
|
||||
ls = 2;
|
||||
}
|
||||
if (ls < -2 || ls > 2) {
|
||||
do_warning_event(event, "bad count (%d)", ls);
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
}
|
||||
parse_arg_add(parse, print_format,
|
||||
PRINT_FMT_ARG_DIGIT, *arg, len_arg, ls);
|
||||
*arg = (*arg)->next;
|
||||
ret++;
|
||||
return ret;
|
||||
case 's':
|
||||
if (!*arg) {
|
||||
do_warning_event(event, "no matching argument");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
goto out_failed;
|
||||
}
|
||||
|
||||
len = ((unsigned long)format + 1) -
|
||||
(unsigned long)start;
|
||||
|
||||
/* should never happen */
|
||||
if (len > 31) {
|
||||
do_warning_event(event, "bad format!");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
len = 31;
|
||||
}
|
||||
|
||||
memcpy(print_format, start, len);
|
||||
print_format[len] = 0;
|
||||
|
||||
parse_arg_add(parse, print_format,
|
||||
PRINT_FMT_ARG_STRING, *arg, len_arg, 0);
|
||||
*arg = (*arg)->next;
|
||||
ret++;
|
||||
return ret;
|
||||
default:
|
||||
snprintf(print_format, 32, ">%c<", *format);
|
||||
parse_arg_add(parse, print_format,
|
||||
PRINT_FMT_STING, NULL, NULL, 0);
|
||||
ret++;
|
||||
return ret;
|
||||
}
|
||||
ret++;
|
||||
}
|
||||
|
||||
out_failed:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int parse_arg_string(struct tep_print_parse **parse, const char *format)
|
||||
{
|
||||
struct trace_seq s;
|
||||
int ret = 0;
|
||||
|
||||
trace_seq_init(&s);
|
||||
for (; *format; format++) {
|
||||
if (*format == '\\') {
|
||||
format++;
|
||||
ret++;
|
||||
switch (*format) {
|
||||
case 'n':
|
||||
trace_seq_putc(&s, '\n');
|
||||
break;
|
||||
case 't':
|
||||
trace_seq_putc(&s, '\t');
|
||||
break;
|
||||
case 'r':
|
||||
trace_seq_putc(&s, '\r');
|
||||
break;
|
||||
case '\\':
|
||||
trace_seq_putc(&s, '\\');
|
||||
break;
|
||||
default:
|
||||
trace_seq_putc(&s, *format);
|
||||
break;
|
||||
}
|
||||
} else if (*format == '%') {
|
||||
if (*(format + 1) == '%') {
|
||||
trace_seq_putc(&s, '%');
|
||||
format++;
|
||||
ret++;
|
||||
} else
|
||||
break;
|
||||
} else
|
||||
trace_seq_putc(&s, *format);
|
||||
|
||||
ret++;
|
||||
}
|
||||
trace_seq_terminate(&s);
|
||||
parse_arg_add(parse, s.buffer, PRINT_FMT_STING, NULL, NULL, 0);
|
||||
trace_seq_destroy(&s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct tep_print_parse *
|
||||
parse_args(struct tep_event *event, const char *format, struct tep_print_arg *arg)
|
||||
{
|
||||
struct tep_print_parse *parse_ret = NULL;
|
||||
struct tep_print_parse **parse = NULL;
|
||||
int ret;
|
||||
int len;
|
||||
|
||||
len = strlen(format);
|
||||
while (*format) {
|
||||
if (!parse_ret)
|
||||
parse = &parse_ret;
|
||||
if (*format == '%' && *(format + 1) != '%')
|
||||
ret = parse_arg_format(parse, event, format, &arg);
|
||||
else
|
||||
ret = parse_arg_string(parse, format);
|
||||
if (*parse)
|
||||
parse = &((*parse)->next);
|
||||
|
||||
len -= ret;
|
||||
if (len > 0)
|
||||
format += ret;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return parse_ret;
|
||||
}
|
||||
|
||||
static void print_event_cache(struct tep_print_parse *parse, struct trace_seq *s,
|
||||
void *data, int size, struct tep_event *event)
|
||||
{
|
||||
int len_arg;
|
||||
|
||||
while (parse) {
|
||||
if (parse->len_as_arg)
|
||||
len_arg = eval_num_arg(data, size, event, parse->len_as_arg);
|
||||
switch (parse->type) {
|
||||
case PRINT_FMT_ARG_DIGIT:
|
||||
print_arg_number(s, parse->format,
|
||||
parse->len_as_arg ? len_arg : -1, data,
|
||||
size, parse->ls, event, parse->arg);
|
||||
break;
|
||||
case PRINT_FMT_ARG_POINTER:
|
||||
print_arg_pointer(s, parse->format,
|
||||
parse->len_as_arg ? len_arg : 1,
|
||||
data, size, event, parse->arg);
|
||||
break;
|
||||
case PRINT_FMT_ARG_STRING:
|
||||
print_arg_string(s, parse->format,
|
||||
parse->len_as_arg ? len_arg : -1,
|
||||
data, size, event, parse->arg);
|
||||
break;
|
||||
case PRINT_FMT_STING:
|
||||
default:
|
||||
trace_seq_printf(s, "%s", parse->format);
|
||||
break;
|
||||
}
|
||||
parse = parse->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void pretty_print(struct trace_seq *s, void *data, int size, struct tep_event *event)
|
||||
{
|
||||
struct tep_handle *tep = event->tep;
|
||||
struct tep_print_fmt *print_fmt = &event->print_fmt;
|
||||
struct tep_print_arg *arg = print_fmt->args;
|
||||
struct tep_print_parse *parse = event->print_fmt.print_cache;
|
||||
struct tep_print_arg *args = NULL;
|
||||
const char *ptr = print_fmt->format;
|
||||
unsigned long long val;
|
||||
const char *saveptr;
|
||||
struct trace_seq p;
|
||||
char *bprint_fmt = NULL;
|
||||
char format[32];
|
||||
int len_as_arg;
|
||||
int len_arg = 0;
|
||||
int len;
|
||||
int ls;
|
||||
int ret;
|
||||
|
||||
if (event->flags & TEP_EVENT_FL_FAILED) {
|
||||
trace_seq_printf(s, "[FAILED TO PARSE]");
|
||||
@ -5281,204 +5746,13 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct tep_e
|
||||
if (event->flags & TEP_EVENT_FL_ISBPRINT) {
|
||||
bprint_fmt = get_bprint_format(data, size, event);
|
||||
args = make_bprint_args(bprint_fmt, data, size, event);
|
||||
arg = args;
|
||||
ptr = bprint_fmt;
|
||||
parse = parse_args(event, bprint_fmt, args);
|
||||
}
|
||||
|
||||
for (; *ptr; ptr++) {
|
||||
ls = 0;
|
||||
if (*ptr == '\\') {
|
||||
ptr++;
|
||||
switch (*ptr) {
|
||||
case 'n':
|
||||
trace_seq_putc(s, '\n');
|
||||
break;
|
||||
case 't':
|
||||
trace_seq_putc(s, '\t');
|
||||
break;
|
||||
case 'r':
|
||||
trace_seq_putc(s, '\r');
|
||||
break;
|
||||
case '\\':
|
||||
trace_seq_putc(s, '\\');
|
||||
break;
|
||||
default:
|
||||
trace_seq_putc(s, *ptr);
|
||||
break;
|
||||
}
|
||||
print_event_cache(parse, s, data, size, event);
|
||||
|
||||
} else if (*ptr == '%') {
|
||||
saveptr = ptr;
|
||||
len_as_arg = 0;
|
||||
cont_process:
|
||||
ptr++;
|
||||
switch (*ptr) {
|
||||
case '%':
|
||||
trace_seq_putc(s, '%');
|
||||
break;
|
||||
case '#':
|
||||
/* FIXME: need to handle properly */
|
||||
goto cont_process;
|
||||
case 'h':
|
||||
ls--;
|
||||
goto cont_process;
|
||||
case 'l':
|
||||
ls++;
|
||||
goto cont_process;
|
||||
case 'L':
|
||||
ls = 2;
|
||||
goto cont_process;
|
||||
case '*':
|
||||
/* The argument is the length. */
|
||||
if (!arg) {
|
||||
do_warning_event(event, "no argument match");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
goto out_failed;
|
||||
}
|
||||
len_arg = eval_num_arg(data, size, event, arg);
|
||||
len_as_arg = 1;
|
||||
arg = arg->next;
|
||||
goto cont_process;
|
||||
case '.':
|
||||
case 'z':
|
||||
case 'Z':
|
||||
case '0' ... '9':
|
||||
case '-':
|
||||
goto cont_process;
|
||||
case 'p':
|
||||
if (arg->type == TEP_PRINT_BSTRING) {
|
||||
if (isalnum(ptr[1]))
|
||||
ptr++;
|
||||
trace_seq_puts(s, arg->string.string);
|
||||
arg = arg->next;
|
||||
break;
|
||||
}
|
||||
ret = print_pointer(s, ptr + 1,
|
||||
len_as_arg ? len_arg : 1,
|
||||
data, size,
|
||||
event, arg);
|
||||
arg = arg->next;
|
||||
if (ret > 0)
|
||||
ptr += ret;
|
||||
break;
|
||||
case 'd':
|
||||
case 'u':
|
||||
case 'i':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'o':
|
||||
if (!arg) {
|
||||
do_warning_event(event, "no argument match");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
goto out_failed;
|
||||
}
|
||||
|
||||
len = ((unsigned long)ptr + 1) -
|
||||
(unsigned long)saveptr;
|
||||
|
||||
/* should never happen */
|
||||
if (len > 31) {
|
||||
do_warning_event(event, "bad format!");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
len = 31;
|
||||
}
|
||||
|
||||
memcpy(format, saveptr, len);
|
||||
format[len] = 0;
|
||||
|
||||
val = eval_num_arg(data, size, event, arg);
|
||||
arg = arg->next;
|
||||
|
||||
if (tep->long_size == 8 && ls == 1 &&
|
||||
sizeof(long) != 8) {
|
||||
char *p;
|
||||
|
||||
/* make %l into %ll */
|
||||
if (ls == 1 && (p = strchr(format, 'l')))
|
||||
memmove(p+1, p, strlen(p)+1);
|
||||
ls = 2;
|
||||
}
|
||||
switch (ls) {
|
||||
case -2:
|
||||
if (len_as_arg)
|
||||
trace_seq_printf(s, format, len_arg, (char)val);
|
||||
else
|
||||
trace_seq_printf(s, format, (char)val);
|
||||
break;
|
||||
case -1:
|
||||
if (len_as_arg)
|
||||
trace_seq_printf(s, format, len_arg, (short)val);
|
||||
else
|
||||
trace_seq_printf(s, format, (short)val);
|
||||
break;
|
||||
case 0:
|
||||
if (len_as_arg)
|
||||
trace_seq_printf(s, format, len_arg, (int)val);
|
||||
else
|
||||
trace_seq_printf(s, format, (int)val);
|
||||
break;
|
||||
case 1:
|
||||
if (len_as_arg)
|
||||
trace_seq_printf(s, format, len_arg, (long)val);
|
||||
else
|
||||
trace_seq_printf(s, format, (long)val);
|
||||
break;
|
||||
case 2:
|
||||
if (len_as_arg)
|
||||
trace_seq_printf(s, format, len_arg,
|
||||
(long long)val);
|
||||
else
|
||||
trace_seq_printf(s, format, (long long)val);
|
||||
break;
|
||||
default:
|
||||
do_warning_event(event, "bad count (%d)", ls);
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (!arg) {
|
||||
do_warning_event(event, "no matching argument");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
goto out_failed;
|
||||
}
|
||||
|
||||
len = ((unsigned long)ptr + 1) -
|
||||
(unsigned long)saveptr;
|
||||
|
||||
/* should never happen */
|
||||
if (len > 31) {
|
||||
do_warning_event(event, "bad format!");
|
||||
event->flags |= TEP_EVENT_FL_FAILED;
|
||||
len = 31;
|
||||
}
|
||||
|
||||
memcpy(format, saveptr, len);
|
||||
format[len] = 0;
|
||||
if (!len_as_arg)
|
||||
len_arg = -1;
|
||||
/* Use helper trace_seq */
|
||||
trace_seq_init(&p);
|
||||
print_str_arg(&p, data, size, event,
|
||||
format, len_arg, arg);
|
||||
trace_seq_terminate(&p);
|
||||
trace_seq_puts(s, p.buffer);
|
||||
trace_seq_destroy(&p);
|
||||
arg = arg->next;
|
||||
break;
|
||||
default:
|
||||
trace_seq_printf(s, ">%c<", *ptr);
|
||||
|
||||
}
|
||||
} else
|
||||
trace_seq_putc(s, *ptr);
|
||||
}
|
||||
|
||||
if (event->flags & TEP_EVENT_FL_FAILED) {
|
||||
out_failed:
|
||||
trace_seq_printf(s, "[FAILED TO PARSE]");
|
||||
}
|
||||
|
||||
if (args) {
|
||||
if (event->flags & TEP_EVENT_FL_ISBPRINT) {
|
||||
free_parse_args(parse);
|
||||
free_args(args);
|
||||
free(bprint_fmt);
|
||||
}
|
||||
@ -6577,9 +6851,13 @@ enum tep_errno __tep_parse_format(struct tep_event **eventp,
|
||||
*list = arg;
|
||||
list = &arg->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(event->flags & TEP_EVENT_FL_ISBPRINT))
|
||||
event->print_fmt.print_cache = parse_args(event,
|
||||
event->print_fmt.format,
|
||||
event->print_fmt.args);
|
||||
|
||||
return 0;
|
||||
|
||||
event_parse_failed:
|
||||
@ -7246,7 +7524,7 @@ void tep_free_event(struct tep_event *event)
|
||||
|
||||
free(event->print_fmt.format);
|
||||
free_args(event->print_fmt.args);
|
||||
|
||||
free_parse_args(event->print_fmt.print_cache);
|
||||
free(event);
|
||||
}
|
||||
|
||||
|
@ -272,9 +272,12 @@ struct tep_print_arg {
|
||||
};
|
||||
};
|
||||
|
||||
struct tep_print_parse;
|
||||
|
||||
struct tep_print_fmt {
|
||||
char *format;
|
||||
struct tep_print_arg *args;
|
||||
struct tep_print_parse *print_cache;
|
||||
};
|
||||
|
||||
struct tep_event {
|
||||
|
Loading…
Reference in New Issue
Block a user