lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:   Fri, 10 Sep 2021 18:54:03 +0200
From:   Daniel Bristot de Oliveira <bristot@...hat.com>
To:     Steven Rostedt <rostedt@...dmis.org>,
        linux-trace-devel@...r.kernel.org
Cc:     linux-kernel@...r.kernel.org, Tom Zanussi <zanussi@...nel.org>,
        Masami Hiramatsu <mhiramat@...nel.org>,
        Namhyung Kim <namhyung@...nel.org>,
        linux-rt-users <linux-rt-users@...r.kernel.org>,
        Clark Williams <williams@...hat.com>
Subject: Re: [PATCH 1/9] tracefs: Add API tracefs_hist_data_parse()

On 8/10/21 10:48 PM, Steven Rostedt wrote:
> From: "Steven Rostedt (VMware)" <rostedt@...dmis.org>
> 
> Add a function tracefs_hist_data_parse() that will take the content of a
> trace event's hist data file, and parse it into a "tracefs_hist_data"
> descriptor that can be used to read the raw data from the file.

Steve,

Is this the latest version?

I am getting this when trying it (the patch 1/9):

[root@f34 libtracefs]# make
  COMPILE FPIC       tracefs-utils.o
  COMPILE FPIC       tracefs-instance.o
  COMPILE FPIC       tracefs-events.o
  COMPILE FPIC       tracefs-tools.o
  COMPILE FPIC       tracefs-marker.o
  COMPILE FPIC       tracefs-kprobes.o
  COMPILE FPIC       tracefs-hist.o
  COMPILE FPIC       tracefs-filter.o
  COMPILE FPIC       sqlhist-lex.o
  COMPILE FPIC       sqlhist.tab.o
  COMPILE FPIC       tracefs-sqlhist.o
make[1]: *** No rule to make target 'hist.l', needed by 'hist-lex.c'.  Stop.
make: *** [Makefile:365: /root/libtracefs/lib/tracefs/libtracefs.so.1.3.dev] Error 2

-- Daniel

> 
> Signed-off-by: Steven Rostedt (VMware) <rostedt@...dmis.org>
> ---
>  include/tracefs.h       |   7 +
>  src/Makefile            |   7 +
>  src/tracefs-hist-data.c | 861 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 875 insertions(+)
>  create mode 100644 src/tracefs-hist-data.c
> 
> diff --git a/include/tracefs.h b/include/tracefs.h
> index 17020de0108a..6bd40d72cb25 100644
> --- a/include/tracefs.h
> +++ b/include/tracefs.h
> @@ -413,6 +413,13 @@ static inline int tracefs_hist_destroy(struct tracefs_instance *instance,
>  	return tracefs_hist_command(instance, hist, TRACEFS_HIST_CMD_DESTROY);
>  }
>  
> +struct tracefs_hist_data;
> +
> +struct tracefs_hist_data *tracefs_hist_data_parse(const char *buffer,
> +						  const char **next_buffer,
> +						  char **err);
> +void tracefs_hist_data_free(struct tracefs_hist_data *hdata);
> +
>  struct tracefs_synth;
>  
>  /*
> diff --git a/src/Makefile b/src/Makefile
> index 9248efc5c7fd..1ab181416b82 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -17,6 +17,10 @@ OBJS += sqlhist-lex.o
>  OBJS += sqlhist.tab.o
>  OBJS += tracefs-sqlhist.o
>  
> +# Order matters for the the two below
> +OBJS += hist-lex.o
> +OBJS += tracefs-hist-data.o
> +
>  OBJS := $(OBJS:%.o=$(bdir)/%.o)
>  DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d)
>  
> @@ -45,6 +49,9 @@ sqlhist.tab.c: sqlhist.y sqlhist.tab.h
>  sqlhist-lex.c: sqlhist.l sqlhist.tab.c
>  	flex -o $@ $<
>  
> +hist-lex.c: hist.l
> +	flex -P hist_ -o $@ $<
> +
>  $(bdir)/%.o: %.c
>  	$(Q)$(call do_fpic_compile)
>  
> diff --git a/src/tracefs-hist-data.c b/src/tracefs-hist-data.c
> new file mode 100644
> index 000000000000..497ab9ce97b4
> --- /dev/null
> +++ b/src/tracefs-hist-data.c
> @@ -0,0 +1,861 @@
> +// SPDX-License-Identifier: LGPL-2.1
> +/*
> + * Copyright (C) 2021 VMware Inc, Steven Rostedt <rostedt@...dmis.org>
> + *
> + * Updates:
> + * Copyright (C) 2021, VMware, Tzvetomir Stoyanov <tz.stoyanov@...il.com>
> + *
> + */
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <dirent.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +
> +#include "tracefs.h"
> +#include "tracefs-local.h"
> +
> +#define HIST_FILE "hist"
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stdarg.h>
> +#include <errno.h>
> +#include <ctype.h>
> +#include <unistd.h>
> +#include <tracefs.h>
> +
> +#include "hist.h"
> +
> +#define offset_of(type, field)	((unsigned long )(&((type *)0)->field))
> +#define container_of(p, type, field) ((type *)((void *)(p) - offset_of(type, field)));
> +
> +extern int hist_lex_init_extra(void *data, void* ptr_yy_globals);
> +extern int hist_lex_destroy(void *scanner);
> +
> +int hist_yyinput(void *extra, char *buf, int max)
> +{
> +	struct hist_data *data = extra;
> +
> +	if (!data || !data->buffer)
> +		return -1;
> +
> +	if (data->buffer_idx + max > data->buffer_size)
> +		max = data->buffer_size - data->buffer_idx;
> +
> +	if (max)
> +		memcpy(buf, data->buffer + data->buffer_idx, max);
> +
> +	data->buffer_idx += max;
> +
> +	return max;
> +}
> +
> +extern int hist_yylex(void *data, void *scanner);
> +
> +static char *name_token(enum yytokentype type)
> +{
> +	switch (type) {
> +	case YYEMPTY:
> +		return "YYEMPTY";
> +	case YYEOF:
> +		return "YYEOF";
> +	case YYerror:
> +		return "YYerror";
> +	case YYUNDEF:
> +		return "YYUNDEF";
> +	case NUMBER:
> +		return "NUMBER";
> +	case HEX:
> +		return "HEX";
> +	case NEWLINE:
> +		return "NEWLINE";
> +	case STRING:
> +		return "STRING";
> +	case KEY_TYPE:
> +		return "KEY_TYPE";
> +	case KEY_VAL:
> +		return "KEY_VAL";
> +	case START_RANGE:
> +		return "START_RANGE";
> +	case RANGE_LINEAR:
> +		return "RANGE_LINEAR";
> +	case RANGE_EXPONENT:
> +		return "RANGE_EXPONENT";
> +	case RAW_VAL:
> +		return "RAW_VAL";
> +	case STACKTRACE:
> +		return "STACKTRACE";
> +	case STACK_ITEM:
> +		return "STACK_ITEM";
> +	case STACK_MOD:
> +		return "STACK_MOD";
> +	case VALUE:
> +		return "VALUE";
> +	case TOTALS:
> +		return "TOTALS";
> +	case HITS:
> +		return "HITS";
> +	case ENTRIES:
> +		return "ENTRIES";
> +	case DROPPED:
> +		return "DROPPED";
> +	case COMMENT:
> +		return "COMMENT";
> +	case COLON:
> +		return "COLON";
> +	case COMMA:
> +		return "COMMA";
> +	}
> +	return NULL;
> +}
> +
> +enum tracefs_bucket_key_type {
> +	TRACEFS_BUCKET_KEY_UNDEF,
> +	TRACEFS_BUCKET_KEY_SINGLE,
> +	TRACEFS_BUCKET_KEY_RANGE,
> +};
> +
> +struct tracefs_hist_bucket_key_single {
> +	long long		val;
> +	char			*sym;
> +};
> +
> +struct tracefs_hist_bucket_key_range {
> +	long long		start;
> +	long long		end;
> +};
> +
> +struct tracefs_hist_bucket_key {
> +	struct tracefs_hist_bucket_key	*next;
> +	enum tracefs_bucket_key_type	type;
> +	union {
> +		struct tracefs_hist_bucket_key_single	single;
> +		struct tracefs_hist_bucket_key_range	range;
> +	};
> +};
> +
> +struct tracefs_hist_bucket_val {
> +	struct tracefs_hist_bucket_val		*next;
> +	long long				val;
> +};
> +
> +struct tracefs_hist_bucket {
> +	struct tracefs_hist_bucket		*next;
> +	struct tracefs_hist_bucket_key		*keys;
> +	struct tracefs_hist_bucket_key		**next_key;
> +	struct tracefs_hist_bucket_val		*vals;
> +	struct tracefs_hist_bucket_val		**next_val;
> +};
> +
> +struct tracefs_hist_data {
> +	char				**key_names;
> +	char				**value_names;
> +	struct tracefs_hist_bucket	*buckets;
> +	struct tracefs_hist_bucket	**next_bucket;
> +	unsigned long long		hits;
> +	unsigned long long		entries;
> +	unsigned long long		dropped;
> +};
> +
> +static int do_comment(struct tracefs_hist_data *hdata, const char *comment)
> +{
> +	return 0;
> +}
> +
> +static int do_key_type(struct tracefs_hist_data *hdata, const char *key)
> +{
> +	char **tmp;
> +
> +	tmp = tracefs_list_add(hdata->key_names, key);
> +	if (!tmp)
> +		return -1;
> +	hdata->key_names = tmp;
> +
> +	return 0;
> +}
> +
> +static int do_value_type(struct tracefs_hist_data *hdata, const char *key)
> +{
> +	char **tmp;
> +
> +	tmp = tracefs_list_add(hdata->value_names, key);
> +	if (!tmp)
> +		return -1;
> +	hdata->value_names = tmp;
> +
> +	return 0;
> +}
> +
> +static int start_new_row(struct tracefs_hist_data *hdata)
> +{
> +	struct tracefs_hist_bucket *bucket;
> +	struct tracefs_hist_bucket_key *key;
> +
> +	bucket = calloc(1, sizeof(*bucket));
> +	if (!bucket)
> +		return -1;
> +
> +	key = calloc(1, sizeof(*key));
> +	if (!key) {
> +		free(bucket);
> +		return -1;
> +	}
> +
> +	bucket->keys = key;
> +	bucket->next_key = &key->next;
> +
> +	bucket->next_val = &bucket->vals;
> +
> +	*hdata->next_bucket = bucket;
> +	hdata->next_bucket = &bucket->next;
> +	return 0;
> +}
> +
> +static int start_new_key(struct tracefs_hist_data *hdata)
> +{
> +	struct tracefs_hist_bucket *bucket;
> +	struct tracefs_hist_bucket_key *key;
> +
> +	bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next);
> +
> +	key = calloc(1, sizeof(*key));
> +	if (!key) {
> +		free(bucket);
> +		return -1;
> +	}
> +
> +	*bucket->next_key = key;
> +	bucket->next_key = &key->next;
> +
> +	return 0;
> +}
> +
> +static char *chomp(char *text)
> +{
> +	char *p;
> +	int len;
> +
> +	while (isspace(*text))
> +		text++;
> +
> +	len = strlen(text);
> +	p = text + len - 1;
> +	while (p >= text && isspace(*p))
> +		p--;
> +
> +	p[1] = '\0';
> +
> +	return text;
> +}
> +
> +static int __do_key_val(struct tracefs_hist_data *hdata,
> +			char *text, const char *delim, const char *end)
> +{
> +	struct tracefs_hist_bucket *bucket;
> +	struct tracefs_hist_bucket_key *key;
> +	struct tracefs_hist_bucket_key_single *k;
> +	char *val;
> +	int len;
> +
> +	text = chomp(text);
> +
> +	bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next);
> +
> +	key = container_of(bucket->next_key, struct tracefs_hist_bucket_key, next);
> +	if (!key->type)
> +		key->type = TRACEFS_BUCKET_KEY_SINGLE;
> +
> +	if (key->type != TRACEFS_BUCKET_KEY_SINGLE)
> +		return -1;
> +
> +	k = &key->single;
> +
> +	len = strlen(text);
> +	len += k->sym ? strlen(k->sym) + strlen(delim) : 0;
> +	if (end)
> +		len += strlen(end);
> +
> +	val = realloc(k->sym, len + 1);
> +	if (!val)
> +		return -1;
> +
> +	if (k->sym)
> +		strcat(val, delim);
> +	else
> +		val[0] = '\0';
> +
> +	strcat(val, text);
> +	if (end)
> +		strcat(val, end);
> +
> +	k->sym = val;
> +
> +	return 0;
> +}
> +
> +static int do_key_val(struct tracefs_hist_data *hdata, char *text)
> +{
> +	return __do_key_val(hdata, text, " ", NULL);
> +}
> +
> +static int do_key_stack(struct tracefs_hist_data *hdata, char *text)
> +{
> +	return __do_key_val(hdata, text, "\n", NULL);
> +}
> +
> +static int do_key_stack_mod(struct tracefs_hist_data *hdata, char *text)
> +{
> +	return __do_key_val(hdata, text, " [", "]");
> +}
> +
> +static int do_key_raw(struct tracefs_hist_data *hdata, char *text)
> +{
> +	struct tracefs_hist_bucket *bucket;
> +	struct tracefs_hist_bucket_key *key;
> +	struct tracefs_hist_bucket_key_single *k;
> +
> +	text = chomp(text);
> +
> +	bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next);
> +
> +	key = container_of(bucket->next_key, struct tracefs_hist_bucket_key, next);
> +	if (key->type != TRACEFS_BUCKET_KEY_SINGLE)
> +		return -1;
> +
> +	k = &key->single;
> +
> +	if (k->val)
> +		return -1;
> +
> +	k->val = strtoll(text, NULL, 0);
> +
> +	return 0;
> +}
> +
> +static int do_key_range(struct tracefs_hist_data *hdata, long long start,
> +			long long end)
> +{
> +	struct tracefs_hist_bucket *bucket;
> +	struct tracefs_hist_bucket_key *key;
> +	struct tracefs_hist_bucket_key_range *k;
> +
> +	bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next);
> +
> +	key = container_of(bucket->next_key, struct tracefs_hist_bucket_key, next);
> +
> +	if (!key->type)
> +		key->type = TRACEFS_BUCKET_KEY_RANGE;
> +
> +	if (key->type != TRACEFS_BUCKET_KEY_RANGE)
> +		return -1;
> +
> +	k = &key->range;
> +
> +	k->start = start;
> +	k->end = end;
> +
> +	return 0;
> +}
> +
> +static int do_value_num(struct tracefs_hist_data *hdata, long long num)
> +{
> +	struct tracefs_hist_bucket *bucket;
> +	struct tracefs_hist_bucket_val *val;
> +
> +	bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next);
> +	val = calloc(1, sizeof(*val));
> +	if (!val)
> +		return -1;
> +
> +	val->val = num;
> +
> +	*bucket->next_val = val;
> +	bucket->next_val = &val->next;
> +
> +	return 0;
> +}
> +
> +static long long expo(unsigned int e, long long exp)
> +{
> +	long long ret;
> +
> +	if (exp < 0)
> +		exp = 0;
> +
> +	if (e == 2)
> +		return 1LL << exp;
> +
> +	ret = 1;
> +	for (; exp > 0; exp--)
> +		ret *= e;
> +	return e;
> +}
> +
> +enum hist_state {
> +	HIST_START,
> +	HIST_KEYS_START,
> +	HIST_KEYS,
> +	HIST_KEY_VALS,
> +	HIST_RANGE,
> +	HIST_VALUES,
> +	HIST_NEXT_KEY,
> +	HIST_STACK,
> +	HIST_ENTRIES,
> +	HIST_DROPPED,
> +	HIST_END,
> +};
> +
> +static const char *find_buffer_line(const char *buffer, int line_no)
> +{
> +	int line = 0;
> +	int i;
> +
> +	for (i = 0; buffer[i]; i++) {
> +		if (buffer[i] == '\n') {
> +			line++;
> +			if (line >= line_no) {
> +				i++;
> +				break;
> +			}
> +		}
> +	}
> +	return buffer + i;
> +}
> +
> +static void print_line(struct trace_seq *seq, struct hist_data *data)
> +{
> +	const char *buffer = data->buffer;
> +	int i;
> +
> +	buffer = find_buffer_line(buffer, data->line_no);
> +
> +	for (i = 0; buffer[i]; i++) {
> +		if (buffer[i] == '\n')
> +			break;
> +	}
> +
> +	trace_seq_printf(seq, "%.*s (line:%d idx:%d)\n", i, buffer,
> +			 data->line_no, data->line_idx);
> +	trace_seq_printf(seq, "%*s\n", data->line_idx, "^");
> +}
> +
> +static void print_error(struct hist_data *data, char **err,
> +			enum hist_state state, enum yytokentype type)
> +{
> +	struct trace_seq seq;
> +	char *tname;
> +
> +	if (!err)
> +		return;
> +
> +	trace_seq_init(&seq);
> +
> +	print_line(&seq, data);
> +
> +	trace_seq_printf(&seq, "Error in ");
> +	switch (state) {
> +	case HIST_START:
> +		trace_seq_printf(&seq, "HIST_START");
> +		break;
> +	case HIST_KEYS_START:
> +		trace_seq_printf(&seq, "HIST_KEYS_START");
> +		break;
> +	case HIST_KEYS:
> +		trace_seq_printf(&seq, "HIST_KEYS");
> +		break;
> +	case HIST_KEY_VALS:
> +		trace_seq_printf(&seq, "HIST_KEY_VALS");
> +		break;
> +	case HIST_RANGE:
> +		trace_seq_printf(&seq, "HIST_RANGE");
> +		break;
> +	case HIST_VALUES:
> +		trace_seq_printf(&seq, "HIST_VALUES");
> +		break;
> +	case HIST_NEXT_KEY:
> +		trace_seq_printf(&seq, "HIST_NEXT_KEY");
> +	case HIST_STACK:
> +		trace_seq_printf(&seq, "HIST_STACK");
> +		break;
> +	case HIST_ENTRIES:
> +		trace_seq_printf(&seq, "HIST_ENTRIES");
> +		break;
> +	case HIST_DROPPED:
> +		trace_seq_printf(&seq, "HIST_DROPPED");
> +		break;
> +	case HIST_END:
> +		trace_seq_printf(&seq, "HIST_END");
> +		break;
> +	}
> +	trace_seq_printf(&seq, " with token ");
> +	tname = name_token(type);
> +	if (tname)
> +		trace_seq_printf(&seq, "%s", tname);
> +	else
> +		trace_seq_printf(&seq, "(unknown %d)", type);
> +
> +	trace_seq_printf(&seq, " last token %s\n", data->text);
> +	trace_seq_terminate(&seq);
> +	if (seq.buffer)
> +		*err = seq.buffer;
> +	seq.buffer = NULL;
> +	trace_seq_destroy(&seq);
> +}
> +
> +static void update_next(const char **next_buffer, struct hist_data *data)
> +{
> +	if (!next_buffer)
> +		return;
> +
> +	*next_buffer = find_buffer_line(data->buffer, data->line_no - 1);
> +}
> +
> +/**
> + * tracefs_hist_data_free - free a created hist data descriptor
> + * @hdata: The tracefs_hist_data descriptor to free.
> + *
> + * Frees the data allocated by tracefs_hist_data_parse().
> + */
> +void tracefs_hist_data_free(struct tracefs_hist_data *hdata)
> +{
> +	struct tracefs_hist_bucket *bucket;
> +	struct tracefs_hist_bucket_key *key;
> +	struct tracefs_hist_bucket_val *val;
> +
> +	if (!hdata)
> +		return;
> +
> +	tracefs_list_free(hdata->key_names);
> +	tracefs_list_free(hdata->value_names);
> +
> +	while ((bucket = hdata->buckets)) {
> +		hdata->buckets = bucket->next;
> +		while ((key = bucket->keys)) {
> +			bucket->keys = key->next;
> +			switch (key->type) {
> +			case TRACEFS_BUCKET_KEY_SINGLE:
> +				free(key->single.sym);
> +				break;
> +			default:
> +				break;
> +			}
> +			free(key);
> +		}
> +		while ((val = bucket->vals)) {
> +			bucket->vals = val->next;
> +			free(val);
> +		}
> +		free(bucket);
> +	}
> +
> +	free(hdata);
> +}
> +
> +/* Used for debugging in gdb */
> +static void breakpoint(char *text)
> +{
> +}
> +
> +/**
> + * tracefs_hist_data_parse - parse a hist file of a trace event
> + * @buffer: The buffer containing the hist file content
> + * @next_buffer: If not NULL will point to the next hist in the buffer
> + * @err: If not NULL, will load the error message on error
> + *
> + * Reads and parses the content of a "hist" file of a trace event.
> + * It will return a descriptor that can be used to read the content and
> + * create a histogram table.
> + *
> + * Because "hist" files may contain more than one histogram, and this
> + * function will only parse one of the histograms, if there are more
> + * than one histogram in the buffer, and @next_buffer is not NULL, then
> + * it will return the location of the next histogram in @next_buffer.
> + *
> + * If there's an error in the parsing, then @err will contain an error
> + * message about what went wrong.
> + *
> + * Returns a desrciptor of a histogram representing the hist file content.
> + * NULL on error.
> + * The descriptor must be freed with tracefs_hist_data_free().
> + */
> +struct tracefs_hist_data *
> +tracefs_hist_data_parse(const char *buffer, const char **next_buffer, char **err)
> +{
> +	struct tracefs_hist_data *hdata;
> +	struct hist_data data;
> +	enum hist_state state = 0;
> +	long long start_range, end_range;
> +	bool first = false;
> +	unsigned int e;
> +	int buffer_size;
> +	bool done = false;
> +	char *text;
> +	enum yytokentype type;
> +	int ret;
> +
> +	if (!buffer)
> +		return NULL;
> +
> +	hdata = calloc(1, sizeof(*hdata));
> +	if (!hdata)
> +		return NULL;
> +
> +	hdata->next_bucket = &hdata->buckets;
> +
> +	memset(&data, 0, sizeof(data));
> +
> +	buffer_size = strlen(buffer);
> +	data.buffer = buffer;
> +	data.buffer_size = buffer_size;
> +	data.text = malloc(buffer_size);
> +	if (!data.text) {
> +		free(hdata);
> +		perror("text");
> +		exit(-1);
> +	}
> +
> +	ret = hist_lex_init_extra(&data, &data.scanner);
> +	if (ret < 0) {
> +		perror("ylex_init");
> +		return NULL;
> +	}
> +	while (!done) {
> +		type = hist_yylex(&data, data.scanner);
> +		if (type < 0)
> +			break;
> +		text = data.text;
> +		breakpoint(text);
> +		switch (state) {
> +		case HIST_START:
> +			switch (type) {
> +			case COMMENT:
> +				first = true;
> +				ret = do_comment(hdata, text);
> +				if (ret < 0)
> +					goto error;
> +				break;
> +			case KEY_TYPE:
> +				goto key_type;
> +			case STACKTRACE:
> +				goto stacktrace;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case HIST_KEYS_START:
> +			switch (type) {
> +			case KEY_TYPE:
> + key_type:
> +				if (first) {
> +					ret = do_key_type(hdata, text);
> +					if (ret < 0)
> +						goto error;
> +				}
> +				ret = start_new_row(hdata);
> +				state = HIST_KEY_VALS;
> +				break;
> +			case STACKTRACE:
> + stacktrace:
> +				if (first) {
> +					ret = do_key_type(hdata, "stacktrace");
> +					if (ret < 0)
> +						goto error;
> +				}
> +				ret = start_new_row(hdata);
> +				state = HIST_STACK;
> +				break;
> +			case HITS:
> +				hdata->hits = strtoll(text, NULL, 0);
> +				state = HIST_ENTRIES;
> +				break;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case HIST_KEYS:
> +			switch (type) {
> +			case KEY_TYPE:
> +				if (first) {
> +					ret = do_key_type(hdata, text);
> +					if (ret < 0)
> +						goto error;
> +				}
> +				ret = start_new_key(hdata);
> +				state = HIST_KEY_VALS;
> +				break;
> +			case STACKTRACE:
> +				if (first) {
> +					ret = do_key_type(hdata, "stacktrace");
> +					if (ret < 0)
> +						goto error;
> +				}
> +				ret = start_new_key(hdata);
> +				state = HIST_STACK;
> +				break;
> +			case NEWLINE:
> +				break;
> +			case COLON:
> +				state = HIST_VALUES;
> +				break;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case HIST_NEXT_KEY:
> +			switch (type) {
> +			case COLON:
> +				state = HIST_VALUES;
> +				break;
> +			case COMMA:
> +				state = HIST_KEYS;
> +				break;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case HIST_KEY_VALS:
> +			switch (type) {
> +			case NEWLINE:
> +				continue;
> +			case START_RANGE:
> +				start_range = strtoll(text, NULL, 0);
> +				state = HIST_RANGE;
> +				break;
> +			case KEY_VAL:
> +				ret = do_key_val(hdata, text);
> +				if (ret < 0)
> +					goto error;
> +				break;
> +			case RAW_VAL:
> +				ret = do_key_raw(hdata, text);
> +				if (ret < 0)
> +					goto error;
> +				state = HIST_NEXT_KEY;
> +				break;
> +			case COLON:
> +				state = HIST_VALUES;
> +				break;
> +			case COMMA:
> +				state = HIST_KEYS;
> +				break;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case HIST_STACK:
> +			switch (type) {
> +			case NEWLINE:
> +				break;
> +			case STACK_ITEM:
> +				ret = do_key_stack(hdata, text);
> +				if (ret < 0)
> +					goto error;
> +				break;
> +			case STACK_MOD:
> +				ret = do_key_stack_mod(hdata, text);
> +				if (ret < 0)
> +					goto error;
> +				break;
> +			case COLON:
> +				state = HIST_VALUES;
> +				break;
> +			case COMMA:
> +				state = HIST_KEYS;
> +				break;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case HIST_RANGE:
> +			switch (type) {
> +			case RANGE_LINEAR:
> +				do_key_range(hdata, start_range,
> +					     strtoll(text, NULL, 0));
> +				break;
> +			case RANGE_EXPONENT:
> +				end_range = strtoll(text, NULL, 0);
> +				e = (unsigned int)start_range;
> +				start_range = expo(e, end_range - 1);
> +				end_range = expo(e, end_range);
> +				do_key_range(hdata, start_range, end_range);
> +				break;
> +			default:
> +				goto error;
> +			}
> +			state = HIST_KEYS;
> +			break;
> +		case HIST_VALUES:
> +			switch (type) {
> +			case VALUE:
> +				if (first) {
> +					ret = do_value_type(hdata, text);
> +					if (ret < 0)
> +						goto error;
> +				}
> +				break;
> +			case NUMBER:
> +				ret = do_value_num(hdata, strtoll(text, NULL, 0));
> +				if (ret < 0)
> +					goto error;
> +				break;
> +			case NEWLINE:
> +				state = HIST_KEYS_START;
> +				first = false;
> +				break;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case HIST_ENTRIES:
> +			switch (type) {
> +			case ENTRIES:
> +				hdata->entries = strtoll(text, NULL, 0);
> +				state = HIST_DROPPED;
> +				break;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case HIST_DROPPED:
> +			switch (type) {
> +			case DROPPED:
> +				hdata->dropped = strtoll(text, NULL, 0);
> +				state = HIST_END;
> +				break;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case HIST_END:
> +			done = true;
> +			switch (type) {
> +			case COMMENT:
> +				update_next(next_buffer, &data);
> +				break;
> +			case YYEOF:
> +				/* Fall through */
> +			default:
> +				/* Do at end, as next_buffer may point to buffer*/
> +				if (next_buffer)
> +					*next_buffer = NULL;
> +				break;
> +			}
> +			break;
> +		}
> +	}
> +
> +	hist_lex_destroy(data.scanner);
> +	free(data.text);
> +
> +	return hdata;
> + error:
> +	print_error(&data, err, state, type);
> +	hist_lex_destroy(data.scanner);
> +	free(data.text);
> +	tracefs_hist_data_free(hdata);
> +	return NULL;
> +}
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ