162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* For general debugging purposes */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <inttypes.h>
562306a36Sopenharmony_ci#include <string.h>
662306a36Sopenharmony_ci#include <stdarg.h>
762306a36Sopenharmony_ci#include <stdio.h>
862306a36Sopenharmony_ci#include <stdlib.h>
962306a36Sopenharmony_ci#include <sys/wait.h>
1062306a36Sopenharmony_ci#include <api/debug.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/time64.h>
1362306a36Sopenharmony_ci#include <sys/time.h>
1462306a36Sopenharmony_ci#ifdef HAVE_BACKTRACE_SUPPORT
1562306a36Sopenharmony_ci#include <execinfo.h>
1662306a36Sopenharmony_ci#endif
1762306a36Sopenharmony_ci#include "color.h"
1862306a36Sopenharmony_ci#include "event.h"
1962306a36Sopenharmony_ci#include "debug.h"
2062306a36Sopenharmony_ci#include "print_binary.h"
2162306a36Sopenharmony_ci#include "target.h"
2262306a36Sopenharmony_ci#include "trace-event.h"
2362306a36Sopenharmony_ci#include "ui/helpline.h"
2462306a36Sopenharmony_ci#include "ui/ui.h"
2562306a36Sopenharmony_ci#include "util/parse-sublevel-options.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <linux/ctype.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
3062306a36Sopenharmony_ci#include <traceevent/event-parse.h>
3162306a36Sopenharmony_ci#else
3262306a36Sopenharmony_ci#define LIBTRACEEVENT_VERSION 0
3362306a36Sopenharmony_ci#endif
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciint verbose;
3662306a36Sopenharmony_ciint debug_peo_args;
3762306a36Sopenharmony_cibool dump_trace = false, quiet = false;
3862306a36Sopenharmony_ciint debug_ordered_events;
3962306a36Sopenharmony_cistatic int redirect_to_stderr;
4062306a36Sopenharmony_ciint debug_data_convert;
4162306a36Sopenharmony_cistatic FILE *debug_file;
4262306a36Sopenharmony_cibool debug_display_time;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_civoid debug_set_file(FILE *file)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	debug_file = file;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_civoid debug_set_display_time(bool set)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	debug_display_time = set;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic int fprintf_time(FILE *file)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct timeval tod;
5762306a36Sopenharmony_ci	struct tm ltime;
5862306a36Sopenharmony_ci	char date[64];
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (!debug_display_time)
6162306a36Sopenharmony_ci		return 0;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (gettimeofday(&tod, NULL) != 0)
6462306a36Sopenharmony_ci		return 0;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (localtime_r(&tod.tv_sec, &ltime) == NULL)
6762306a36Sopenharmony_ci		return 0;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	strftime(date, sizeof(date),  "%F %H:%M:%S", &ltime);
7062306a36Sopenharmony_ci	return fprintf(file, "[%s.%06lu] ", date, (long)tod.tv_usec);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciint veprintf(int level, int var, const char *fmt, va_list args)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	int ret = 0;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (var >= level) {
7862306a36Sopenharmony_ci		if (use_browser >= 1 && !redirect_to_stderr) {
7962306a36Sopenharmony_ci			ui_helpline__vshow(fmt, args);
8062306a36Sopenharmony_ci		} else {
8162306a36Sopenharmony_ci			ret = fprintf_time(debug_file);
8262306a36Sopenharmony_ci			ret += vfprintf(debug_file, fmt, args);
8362306a36Sopenharmony_ci		}
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return ret;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ciint eprintf(int level, int var, const char *fmt, ...)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	va_list args;
9262306a36Sopenharmony_ci	int ret;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	va_start(args, fmt);
9562306a36Sopenharmony_ci	ret = veprintf(level, var, fmt, args);
9662306a36Sopenharmony_ci	va_end(args);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return ret;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int veprintf_time(u64 t, const char *fmt, va_list args)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	int ret = 0;
10462306a36Sopenharmony_ci	u64 secs, usecs, nsecs = t;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	secs   = nsecs / NSEC_PER_SEC;
10762306a36Sopenharmony_ci	nsecs -= secs  * NSEC_PER_SEC;
10862306a36Sopenharmony_ci	usecs  = nsecs / NSEC_PER_USEC;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
11162306a36Sopenharmony_ci		      secs, usecs);
11262306a36Sopenharmony_ci	ret += vfprintf(stderr, fmt, args);
11362306a36Sopenharmony_ci	return ret;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciint eprintf_time(int level, int var, u64 t, const char *fmt, ...)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	int ret = 0;
11962306a36Sopenharmony_ci	va_list args;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (var >= level) {
12262306a36Sopenharmony_ci		va_start(args, fmt);
12362306a36Sopenharmony_ci		ret = veprintf_time(t, fmt, args);
12462306a36Sopenharmony_ci		va_end(args);
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return ret;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/*
13162306a36Sopenharmony_ci * Overloading libtraceevent standard info print
13262306a36Sopenharmony_ci * function, display with -v in perf.
13362306a36Sopenharmony_ci */
13462306a36Sopenharmony_civoid pr_stat(const char *fmt, ...)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	va_list args;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	va_start(args, fmt);
13962306a36Sopenharmony_ci	veprintf(1, verbose, fmt, args);
14062306a36Sopenharmony_ci	va_end(args);
14162306a36Sopenharmony_ci	eprintf(1, verbose, "\n");
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ciint dump_printf(const char *fmt, ...)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	va_list args;
14762306a36Sopenharmony_ci	int ret = 0;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (dump_trace) {
15062306a36Sopenharmony_ci		va_start(args, fmt);
15162306a36Sopenharmony_ci		ret = vprintf(fmt, args);
15262306a36Sopenharmony_ci		va_end(args);
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return ret;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic int trace_event_printer(enum binary_printer_ops op,
15962306a36Sopenharmony_ci			       unsigned int val, void *extra, FILE *fp)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	const char *color = PERF_COLOR_BLUE;
16262306a36Sopenharmony_ci	union perf_event *event = (union perf_event *)extra;
16362306a36Sopenharmony_ci	unsigned char ch = (unsigned char)val;
16462306a36Sopenharmony_ci	int printed = 0;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	switch (op) {
16762306a36Sopenharmony_ci	case BINARY_PRINT_DATA_BEGIN:
16862306a36Sopenharmony_ci		printed += fprintf(fp, ".");
16962306a36Sopenharmony_ci		printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n",
17062306a36Sopenharmony_ci					 event->header.size);
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci	case BINARY_PRINT_LINE_BEGIN:
17362306a36Sopenharmony_ci		printed += fprintf(fp, ".");
17462306a36Sopenharmony_ci		break;
17562306a36Sopenharmony_ci	case BINARY_PRINT_ADDR:
17662306a36Sopenharmony_ci		printed += color_fprintf(fp, color, "  %04x: ", val);
17762306a36Sopenharmony_ci		break;
17862306a36Sopenharmony_ci	case BINARY_PRINT_NUM_DATA:
17962306a36Sopenharmony_ci		printed += color_fprintf(fp, color, " %02x", val);
18062306a36Sopenharmony_ci		break;
18162306a36Sopenharmony_ci	case BINARY_PRINT_NUM_PAD:
18262306a36Sopenharmony_ci		printed += color_fprintf(fp, color, "   ");
18362306a36Sopenharmony_ci		break;
18462306a36Sopenharmony_ci	case BINARY_PRINT_SEP:
18562306a36Sopenharmony_ci		printed += color_fprintf(fp, color, "  ");
18662306a36Sopenharmony_ci		break;
18762306a36Sopenharmony_ci	case BINARY_PRINT_CHAR_DATA:
18862306a36Sopenharmony_ci		printed += color_fprintf(fp, color, "%c",
18962306a36Sopenharmony_ci			      isprint(ch) && isascii(ch) ? ch : '.');
19062306a36Sopenharmony_ci		break;
19162306a36Sopenharmony_ci	case BINARY_PRINT_CHAR_PAD:
19262306a36Sopenharmony_ci		printed += color_fprintf(fp, color, " ");
19362306a36Sopenharmony_ci		break;
19462306a36Sopenharmony_ci	case BINARY_PRINT_LINE_END:
19562306a36Sopenharmony_ci		printed += color_fprintf(fp, color, "\n");
19662306a36Sopenharmony_ci		break;
19762306a36Sopenharmony_ci	case BINARY_PRINT_DATA_END:
19862306a36Sopenharmony_ci		printed += fprintf(fp, "\n");
19962306a36Sopenharmony_ci		break;
20062306a36Sopenharmony_ci	default:
20162306a36Sopenharmony_ci		break;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return printed;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_civoid trace_event(union perf_event *event)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	unsigned char *raw_event = (void *)event;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (!dump_trace)
21262306a36Sopenharmony_ci		return;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	print_binary(raw_event, event->header.size, 16,
21562306a36Sopenharmony_ci		     trace_event_printer, event);
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic struct sublevel_option debug_opts[] = {
21962306a36Sopenharmony_ci	{ .name = "verbose",		.value_ptr = &verbose },
22062306a36Sopenharmony_ci	{ .name = "ordered-events",	.value_ptr = &debug_ordered_events},
22162306a36Sopenharmony_ci	{ .name = "stderr",		.value_ptr = &redirect_to_stderr},
22262306a36Sopenharmony_ci	{ .name = "data-convert",	.value_ptr = &debug_data_convert },
22362306a36Sopenharmony_ci	{ .name = "perf-event-open",	.value_ptr = &debug_peo_args },
22462306a36Sopenharmony_ci	{ .name = NULL, }
22562306a36Sopenharmony_ci};
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ciint perf_debug_option(const char *str)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	int ret;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	ret = perf_parse_sublevel_options(str, debug_opts);
23262306a36Sopenharmony_ci	if (ret)
23362306a36Sopenharmony_ci		return ret;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* Allow only verbose value in range (0, 10), otherwise set 0. */
23662306a36Sopenharmony_ci	verbose = (verbose < 0) || (verbose > 10) ? 0 : verbose;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci#if LIBTRACEEVENT_VERSION >= MAKE_LIBTRACEEVENT_VERSION(1, 3, 0)
23962306a36Sopenharmony_ci	if (verbose == 1)
24062306a36Sopenharmony_ci		tep_set_loglevel(TEP_LOG_INFO);
24162306a36Sopenharmony_ci	else if (verbose == 2)
24262306a36Sopenharmony_ci		tep_set_loglevel(TEP_LOG_DEBUG);
24362306a36Sopenharmony_ci	else if (verbose >= 3)
24462306a36Sopenharmony_ci		tep_set_loglevel(TEP_LOG_ALL);
24562306a36Sopenharmony_ci#endif
24662306a36Sopenharmony_ci	return 0;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ciint perf_quiet_option(void)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct sublevel_option *opt = &debug_opts[0];
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* disable all debug messages */
25462306a36Sopenharmony_ci	while (opt->name) {
25562306a36Sopenharmony_ci		*opt->value_ptr = -1;
25662306a36Sopenharmony_ci		opt++;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/* For debug variables that are used as bool types, set to 0. */
26062306a36Sopenharmony_ci	redirect_to_stderr = 0;
26162306a36Sopenharmony_ci	debug_peo_args = 0;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	return 0;
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci#define DEBUG_WRAPPER(__n, __l)				\
26762306a36Sopenharmony_cistatic int pr_ ## __n ## _wrapper(const char *fmt, ...)	\
26862306a36Sopenharmony_ci{							\
26962306a36Sopenharmony_ci	va_list args;					\
27062306a36Sopenharmony_ci	int ret;					\
27162306a36Sopenharmony_ci							\
27262306a36Sopenharmony_ci	va_start(args, fmt);				\
27362306a36Sopenharmony_ci	ret = veprintf(__l, verbose, fmt, args);	\
27462306a36Sopenharmony_ci	va_end(args);					\
27562306a36Sopenharmony_ci	return ret;					\
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciDEBUG_WRAPPER(warning, 0);
27962306a36Sopenharmony_ciDEBUG_WRAPPER(debug, 1);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_civoid perf_debug_setup(void)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	debug_set_file(stderr);
28462306a36Sopenharmony_ci	libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci/* Obtain a backtrace and print it to stdout. */
28862306a36Sopenharmony_ci#ifdef HAVE_BACKTRACE_SUPPORT
28962306a36Sopenharmony_civoid dump_stack(void)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	void *array[16];
29262306a36Sopenharmony_ci	size_t size = backtrace(array, ARRAY_SIZE(array));
29362306a36Sopenharmony_ci	char **strings = backtrace_symbols(array, size);
29462306a36Sopenharmony_ci	size_t i;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	printf("Obtained %zd stack frames.\n", size);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	for (i = 0; i < size; i++)
29962306a36Sopenharmony_ci		printf("%s\n", strings[i]);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	free(strings);
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci#else
30462306a36Sopenharmony_civoid dump_stack(void) {}
30562306a36Sopenharmony_ci#endif
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_civoid sighandler_dump_stack(int sig)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	psignal(sig, "perf");
31062306a36Sopenharmony_ci	dump_stack();
31162306a36Sopenharmony_ci	signal(sig, SIG_DFL);
31262306a36Sopenharmony_ci	raise(sig);
31362306a36Sopenharmony_ci}
314