diff options
Diffstat (limited to 'tools/lib/traceevent/event-parse.c')
| -rw-r--r-- | tools/lib/traceevent/event-parse.c | 1004 | 
1 files changed, 749 insertions, 255 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index ba4f33804af1..3ba566de821c 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -4565,43 +4565,93 @@ get_bprint_format(void *data, int size __maybe_unused,  	return format;  } -static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size, -			  struct tep_event *event, struct tep_print_arg *arg) +static int print_mac_arg(struct trace_seq *s, const char *format, +			 void *data, int size, struct tep_event *event, +			 struct tep_print_arg *arg)  { -	unsigned char *buf;  	const char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"; +	bool reverse = false; +	unsigned char *buf; +	int ret = 0;  	if (arg->type == TEP_PRINT_FUNC) {  		process_defined_func(s, data, size, event, arg); -		return; +		return 0;  	}  	if (arg->type != TEP_PRINT_FIELD) {  		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d",  				 arg->type); -		return; +		return 0;  	} -	if (mac == 'm') +	if (format[0] == 'm') {  		fmt = "%.2x%.2x%.2x%.2x%.2x%.2x"; +	} else if (format[0] == 'M' && format[1] == 'F') { +		fmt = "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x"; +		ret++; +	} +	if (format[1] == 'R') { +		reverse = true; +		ret++; +	} +  	if (!arg->field.field) {  		arg->field.field =  			tep_find_any_field(event, arg->field.name);  		if (!arg->field.field) {  			do_warning_event(event, "%s: field %s not found",  					 __func__, arg->field.name); -			return; +			return ret;  		}  	}  	if (arg->field.field->size != 6) {  		trace_seq_printf(s, "INVALIDMAC"); -		return; +		return ret;  	} +  	buf = data + arg->field.field->offset; -	trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); +	if (reverse) +		trace_seq_printf(s, fmt, buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); +	else +		trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + +	return ret;  } -static void print_ip4_addr(struct trace_seq *s, char i, unsigned char *buf) +static int parse_ip4_print_args(struct tep_handle *tep, +				const char *ptr, bool *reverse) +{ +	int ret = 0; + +	*reverse = false; + +	/* hnbl */ +	switch (*ptr) { +	case 'h': +		if (tep->file_bigendian) +			*reverse = false; +		else +			*reverse = true; +		ret++; +		break; +	case 'l': +		*reverse = true; +		ret++; +		break; +	case 'n': +	case 'b': +		ret++; +		/* fall through */ +	default: +		*reverse = false; +		break; +	} + +	return ret; +} + +static void print_ip4_addr(struct trace_seq *s, char i, bool reverse, unsigned char *buf)  {  	const char *fmt; @@ -4610,7 +4660,11 @@ static void print_ip4_addr(struct trace_seq *s, char i, unsigned char *buf)  	else  		fmt = "%d.%d.%d.%d"; -	trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3]); +	if (reverse) +		trace_seq_printf(s, fmt, buf[3], buf[2], buf[1], buf[0]); +	else +		trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3]); +  }  static inline bool ipv6_addr_v4mapped(const struct in6_addr *a) @@ -4693,7 +4747,7 @@ static void print_ip6c_addr(struct trace_seq *s, unsigned char *addr)  	if (useIPv4) {  		if (needcolon)  			trace_seq_printf(s, ":"); -		print_ip4_addr(s, 'I', &in6.s6_addr[12]); +		print_ip4_addr(s, 'I', false, &in6.s6_addr[12]);  	}  	return; @@ -4722,16 +4776,20 @@ static int print_ipv4_arg(struct trace_seq *s, const char *ptr, char i,  			  void *data, int size, struct tep_event *event,  			  struct tep_print_arg *arg)  { +	bool reverse = false;  	unsigned char *buf; +	int ret; + +	ret = parse_ip4_print_args(event->tep, ptr, &reverse);  	if (arg->type == TEP_PRINT_FUNC) {  		process_defined_func(s, data, size, event, arg); -		return 0; +		return ret;  	}  	if (arg->type != TEP_PRINT_FIELD) {  		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type); -		return 0; +		return ret;  	}  	if (!arg->field.field) { @@ -4740,7 +4798,7 @@ static int print_ipv4_arg(struct trace_seq *s, const char *ptr, char i,  		if (!arg->field.field) {  			do_warning("%s: field %s not found",  				   __func__, arg->field.name); -			return 0; +			return ret;  		}  	} @@ -4748,11 +4806,12 @@ static int print_ipv4_arg(struct trace_seq *s, const char *ptr, char i,  	if (arg->field.field->size != 4) {  		trace_seq_printf(s, "INVALIDIPv4"); -		return 0; +		return ret;  	} -	print_ip4_addr(s, i, buf); -	return 0; +	print_ip4_addr(s, i, reverse, buf); +	return ret; +  }  static int print_ipv6_arg(struct trace_seq *s, const char *ptr, char i, @@ -4812,7 +4871,9 @@ static int print_ipsa_arg(struct trace_seq *s, const char *ptr, char i,  	char have_c = 0, have_p = 0;  	unsigned char *buf;  	struct sockaddr_storage *sa; +	bool reverse = false;  	int rc = 0; +	int ret;  	/* pISpc */  	if (i == 'I') { @@ -4827,6 +4888,9 @@ static int print_ipsa_arg(struct trace_seq *s, const char *ptr, char i,  			rc++;  		}  	} +	ret = parse_ip4_print_args(event->tep, ptr, &reverse); +	ptr += ret; +	rc += ret;  	if (arg->type == TEP_PRINT_FUNC) {  		process_defined_func(s, data, size, event, arg); @@ -4858,7 +4922,7 @@ static int print_ipsa_arg(struct trace_seq *s, const char *ptr, char i,  			return rc;  		} -		print_ip4_addr(s, i, (unsigned char *) &sa4->sin_addr); +		print_ip4_addr(s, i, reverse, (unsigned char *) &sa4->sin_addr);  		if (have_p)  			trace_seq_printf(s, ":%d", ntohs(sa4->sin_port)); @@ -4892,25 +4956,20 @@ static int print_ip_arg(struct trace_seq *s, const char *ptr,  			struct tep_print_arg *arg)  {  	char i = *ptr;  /* 'i' or 'I' */ -	char ver; -	int rc = 0; +	int rc = 1; +	/* IP version */  	ptr++; -	rc++; -	ver = *ptr; -	ptr++; -	rc++; - -	switch (ver) { +	switch (*ptr) {  	case '4': -		rc += print_ipv4_arg(s, ptr, i, data, size, event, arg); +		rc += print_ipv4_arg(s, ptr + 1, i, data, size, event, arg);  		break;  	case '6': -		rc += print_ipv6_arg(s, ptr, i, data, size, event, arg); +		rc += print_ipv6_arg(s, ptr + 1, i, data, size, event, arg);  		break;  	case 'S': -		rc += print_ipsa_arg(s, ptr, i, data, size, event, arg); +		rc += print_ipsa_arg(s, ptr + 1, i, data, size, event, arg);  		break;  	default:  		return 0; @@ -4919,6 +4978,133 @@ static int print_ip_arg(struct trace_seq *s, const char *ptr,  	return rc;  } +static const int guid_index[16] = {3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15}; +static const int uuid_index[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + +static int print_uuid_arg(struct trace_seq *s, const char *ptr, +			void *data, int size, struct tep_event *event, +			struct tep_print_arg *arg) +{ +	const int *index = uuid_index; +	char *format = "%02x"; +	int ret = 0; +	char *buf; +	int i; + +	switch (*(ptr + 1)) { +	case 'L': +		format = "%02X"; +		/* fall through */ +	case 'l': +		index = guid_index; +		ret++; +		break; +	case 'B': +		format = "%02X"; +		/* fall through */ +	case 'b': +		ret++; +		break; +	} + +	if (arg->type == TEP_PRINT_FUNC) { +		process_defined_func(s, data, size, event, arg); +		return ret; +	} + +	if (arg->type != TEP_PRINT_FIELD) { +		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type); +		return ret; +	} + +	if (!arg->field.field) { +		arg->field.field = +			tep_find_any_field(event, arg->field.name); +		if (!arg->field.field) { +			do_warning("%s: field %s not found", +				   __func__, arg->field.name); +			return ret; +		} +	} + +	if (arg->field.field->size != 16) { +		trace_seq_printf(s, "INVALIDUUID"); +		return ret; +	} + +	buf = data + arg->field.field->offset; + +	for (i = 0; i < 16; i++) { +		trace_seq_printf(s, format, buf[index[i]] & 0xff); +		switch (i) { +		case 3: +		case 5: +		case 7: +		case 9: +			trace_seq_printf(s, "-"); +			break; +		} +	} + +	return ret; +} + +static int print_raw_buff_arg(struct trace_seq *s, const char *ptr, +			      void *data, int size, struct tep_event *event, +			      struct tep_print_arg *arg, int print_len) +{ +	int plen = print_len; +	char *delim = " "; +	int ret = 0; +	char *buf; +	int i; +	unsigned long offset; +	int arr_len; + +	switch (*(ptr + 1)) { +	case 'C': +		delim = ":"; +		ret++; +		break; +	case 'D': +		delim = "-"; +		ret++; +		break; +	case 'N': +		delim = ""; +		ret++; +		break; +	} + +	if (arg->type == TEP_PRINT_FUNC) { +		process_defined_func(s, data, size, event, arg); +		return ret; +	} + +	if (arg->type != TEP_PRINT_DYNAMIC_ARRAY) { +		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type); +		return ret; +	} + +	offset = tep_read_number(event->tep, +				 data + arg->dynarray.field->offset, +				 arg->dynarray.field->size); +	arr_len = (unsigned long long)(offset >> 16); +	buf = data + (offset & 0xffff); + +	if (arr_len < plen) +		plen = arr_len; + +	if (plen < 1) +		return ret; + +	trace_seq_printf(s, "%02x", buf[0] & 0xff); +	for (i = 1; i < plen; i++) +		trace_seq_printf(s, "%s%02x", delim, buf[i] & 0xff); + +	return ret; +} +  static int is_printable_array(char *p, unsigned int len)  {  	unsigned int i; @@ -5007,264 +5193,567 @@ void tep_print_fields(struct trace_seq *s, void *data,  	}  } -static void pretty_print(struct trace_seq *s, void *data, int size, struct tep_event *event) +static int print_function(struct trace_seq *s, const char *format, +			  void *data, int size, struct tep_event *event, +			  struct tep_print_arg *arg)  { -	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_arg *args = NULL; -	const char *ptr = print_fmt->format; -	unsigned long long val;  	struct func_map *func; -	const char *saveptr; -	struct trace_seq p; -	char *bprint_fmt = NULL; -	char format[32]; -	int show_func; -	int len_as_arg; -	int len_arg = 0; -	int len; -	int ls; +	unsigned long long val; -	if (event->flags & TEP_EVENT_FL_FAILED) { -		trace_seq_printf(s, "[FAILED TO PARSE]"); -		tep_print_fields(s, data, size, event); -		return; +	val = eval_num_arg(data, size, event, arg); +	func = find_func(event->tep, val); +	if (func) { +		trace_seq_puts(s, func->func); +		if (*format == 'F' || *format == 'S') +			trace_seq_printf(s, "+0x%llx", val - func->addr); +	} else { +		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 (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; +	return 0; +} + +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++;  	} -	for (; *ptr; ptr++) { -		ls = 0; -		if (*ptr == '\\') { -			ptr++; -			switch (*ptr) { +	switch (*format) { +	case 'F': +	case 'f': +	case 'S': +	case 's': +		ret += print_function(s, format, data, size, event, arg); +		break; +	case 'M': +	case 'm': +		ret += print_mac_arg(s, format, data, size, event, arg); +		break; +	case 'I': +	case 'i': +		ret += print_ip_arg(s, format, data, size, event, arg); +		break; +	case 'U': +		ret += print_uuid_arg(s, format, data, size, event, arg); +		break; +	case 'h': +		ret += print_raw_buff_arg(s, format, data, size, event, arg, plen); +		break; +	default: +		ret = 0; +		val = eval_num_arg(data, size, event, arg); +		trace_seq_printf(s, "%p", (void *)val); +		break; +	} + +	return ret; + +} + +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': -				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, '\\'); +			case 'l': +			case 'b': +				ret++; +				index++;  				break; -			default: -				trace_seq_putc(s, *ptr); +			} +			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; +	} -		} else if (*ptr == '%') { -			saveptr = ptr; -			show_func = 0; -			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 (tep->long_size == 4) -					ls = 1; -				else -					ls = 2; +	return ret; +} -				if (isalnum(ptr[1])) -					ptr++; +static void free_parse_args(struct tep_print_parse *arg) +{ +	struct tep_print_parse *del; -				if (arg->type == TEP_PRINT_BSTRING) { -					trace_seq_puts(s, arg->string.string); -					arg = arg->next; -					break; -				} +	while (arg) { +		del = arg; +		arg = del->next; +		free(del->format); +		free(del); +	} +} -				if (*ptr == 'F' || *ptr == 'f' || -				    *ptr == 'S' || *ptr == 's') { -					show_func = *ptr; -				} else if (*ptr == 'M' || *ptr == 'm') { -					print_mac_arg(s, *ptr, data, size, event, arg); -					arg = arg->next; -					break; -				} else if (*ptr == 'I' || *ptr == 'i') { -					int n; +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; -					n = print_ip_arg(s, ptr, data, size, event, arg); -					if (n > 0) { -						ptr += n - 1; -						arg = arg->next; -						break; -					} -				} +	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; +} -				/* fall through */ -			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; -				} +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; -				len = ((unsigned long)ptr + 1) - -					(unsigned long)saveptr; +	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; -				/* should never happen */ -				if (len > 31) { -					do_warning_event(event, "bad format!"); -					event->flags |= TEP_EVENT_FL_FAILED; -					len = 31; -				} +			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; +			} -				memcpy(format, saveptr, len); -				format[len] = 0; +			len = ((unsigned long)format + 1) - +				(unsigned long)start; -				val = eval_num_arg(data, size, event, arg); -				arg = arg->next; +			/* 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 (show_func) { -					func = find_func(tep, val); -					if (func) { -						trace_seq_puts(s, func->func); -						if (show_func == 'F') -							trace_seq_printf(s, -							       "+0x%llx", -							       val - func->addr); -						break; -					} -				} -				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); -					else if (strcmp(format, "%p") == 0) -						strcpy(format, "0x%llx"); -					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; -				} +			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)ptr + 1) - -					(unsigned long)saveptr; +			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; -				} +			/* 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_STRING, NULL, NULL, 0); +			ret++; +			return ret; +		} +		ret++; +	} + +out_failed: +	return ret; -				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; +} + +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_printf(s, ">%c<", *ptr); - +				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, *ptr); +			trace_seq_putc(&s, *format); + +		ret++; +	} +	trace_seq_terminate(&s); +	parse_arg_add(parse, s.buffer, PRINT_FMT_STRING, 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_STRING: +		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_print_parse *parse = event->print_fmt.print_cache; +	struct tep_print_arg *args = NULL; +	char *bprint_fmt = NULL;  	if (event->flags & TEP_EVENT_FL_FAILED) { -out_failed:  		trace_seq_printf(s, "[FAILED TO PARSE]"); +		tep_print_fields(s, data, size, event); +		return;  	} -	if (args) { +	if (event->flags & TEP_EVENT_FL_ISBPRINT) { +		bprint_fmt = get_bprint_format(data, size, event); +		args = make_bprint_args(bprint_fmt, data, size, event); +		parse = parse_args(event, bprint_fmt, args); +	} + +	print_event_cache(parse, s, data, size, event); + +	if (event->flags & TEP_EVENT_FL_ISBPRINT) { +		free_parse_args(parse);  		free_args(args);  		free(bprint_fmt);  	} @@ -6363,9 +6852,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: @@ -7032,7 +7525,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);  } @@ -7120,6 +7613,7 @@ void tep_free(struct tep_handle *tep)  	free(tep->events);  	free(tep->sort_events);  	free(tep->func_resolver); +	tep_free_plugin_paths(tep);  	free(tep);  }  |