xref: /kernel/linux/linux-5.10/tools/perf/util/debug.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* For general debugging purposes */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <inttypes.h>
58c2ecf20Sopenharmony_ci#include <string.h>
68c2ecf20Sopenharmony_ci#include <stdarg.h>
78c2ecf20Sopenharmony_ci#include <stdio.h>
88c2ecf20Sopenharmony_ci#include <stdlib.h>
98c2ecf20Sopenharmony_ci#include <sys/wait.h>
108c2ecf20Sopenharmony_ci#include <api/debug.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/time64.h>
138c2ecf20Sopenharmony_ci#ifdef HAVE_BACKTRACE_SUPPORT
148c2ecf20Sopenharmony_ci#include <execinfo.h>
158c2ecf20Sopenharmony_ci#endif
168c2ecf20Sopenharmony_ci#include "color.h"
178c2ecf20Sopenharmony_ci#include "event.h"
188c2ecf20Sopenharmony_ci#include "debug.h"
198c2ecf20Sopenharmony_ci#include "print_binary.h"
208c2ecf20Sopenharmony_ci#include "target.h"
218c2ecf20Sopenharmony_ci#include "ui/helpline.h"
228c2ecf20Sopenharmony_ci#include "ui/ui.h"
238c2ecf20Sopenharmony_ci#include "util/parse-sublevel-options.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/ctype.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ciint verbose;
288c2ecf20Sopenharmony_ciint debug_peo_args;
298c2ecf20Sopenharmony_cibool dump_trace = false, quiet = false;
308c2ecf20Sopenharmony_ciint debug_ordered_events;
318c2ecf20Sopenharmony_cistatic int redirect_to_stderr;
328c2ecf20Sopenharmony_ciint debug_data_convert;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ciint veprintf(int level, int var, const char *fmt, va_list args)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	int ret = 0;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	if (var >= level) {
398c2ecf20Sopenharmony_ci		if (use_browser >= 1 && !redirect_to_stderr)
408c2ecf20Sopenharmony_ci			ui_helpline__vshow(fmt, args);
418c2ecf20Sopenharmony_ci		else
428c2ecf20Sopenharmony_ci			ret = vfprintf(stderr, fmt, args);
438c2ecf20Sopenharmony_ci	}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	return ret;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciint eprintf(int level, int var, const char *fmt, ...)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	va_list args;
518c2ecf20Sopenharmony_ci	int ret;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	va_start(args, fmt);
548c2ecf20Sopenharmony_ci	ret = veprintf(level, var, fmt, args);
558c2ecf20Sopenharmony_ci	va_end(args);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	return ret;
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic int veprintf_time(u64 t, const char *fmt, va_list args)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	int ret = 0;
638c2ecf20Sopenharmony_ci	u64 secs, usecs, nsecs = t;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	secs   = nsecs / NSEC_PER_SEC;
668c2ecf20Sopenharmony_ci	nsecs -= secs  * NSEC_PER_SEC;
678c2ecf20Sopenharmony_ci	usecs  = nsecs / NSEC_PER_USEC;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
708c2ecf20Sopenharmony_ci		      secs, usecs);
718c2ecf20Sopenharmony_ci	ret += vfprintf(stderr, fmt, args);
728c2ecf20Sopenharmony_ci	return ret;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciint eprintf_time(int level, int var, u64 t, const char *fmt, ...)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	int ret = 0;
788c2ecf20Sopenharmony_ci	va_list args;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (var >= level) {
818c2ecf20Sopenharmony_ci		va_start(args, fmt);
828c2ecf20Sopenharmony_ci		ret = veprintf_time(t, fmt, args);
838c2ecf20Sopenharmony_ci		va_end(args);
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	return ret;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/*
908c2ecf20Sopenharmony_ci * Overloading libtraceevent standard info print
918c2ecf20Sopenharmony_ci * function, display with -v in perf.
928c2ecf20Sopenharmony_ci */
938c2ecf20Sopenharmony_civoid pr_stat(const char *fmt, ...)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	va_list args;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	va_start(args, fmt);
988c2ecf20Sopenharmony_ci	veprintf(1, verbose, fmt, args);
998c2ecf20Sopenharmony_ci	va_end(args);
1008c2ecf20Sopenharmony_ci	eprintf(1, verbose, "\n");
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ciint dump_printf(const char *fmt, ...)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	va_list args;
1068c2ecf20Sopenharmony_ci	int ret = 0;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (dump_trace) {
1098c2ecf20Sopenharmony_ci		va_start(args, fmt);
1108c2ecf20Sopenharmony_ci		ret = vprintf(fmt, args);
1118c2ecf20Sopenharmony_ci		va_end(args);
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return ret;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int trace_event_printer(enum binary_printer_ops op,
1188c2ecf20Sopenharmony_ci			       unsigned int val, void *extra, FILE *fp)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	const char *color = PERF_COLOR_BLUE;
1218c2ecf20Sopenharmony_ci	union perf_event *event = (union perf_event *)extra;
1228c2ecf20Sopenharmony_ci	unsigned char ch = (unsigned char)val;
1238c2ecf20Sopenharmony_ci	int printed = 0;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	switch (op) {
1268c2ecf20Sopenharmony_ci	case BINARY_PRINT_DATA_BEGIN:
1278c2ecf20Sopenharmony_ci		printed += fprintf(fp, ".");
1288c2ecf20Sopenharmony_ci		printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n",
1298c2ecf20Sopenharmony_ci					 event->header.size);
1308c2ecf20Sopenharmony_ci		break;
1318c2ecf20Sopenharmony_ci	case BINARY_PRINT_LINE_BEGIN:
1328c2ecf20Sopenharmony_ci		printed += fprintf(fp, ".");
1338c2ecf20Sopenharmony_ci		break;
1348c2ecf20Sopenharmony_ci	case BINARY_PRINT_ADDR:
1358c2ecf20Sopenharmony_ci		printed += color_fprintf(fp, color, "  %04x: ", val);
1368c2ecf20Sopenharmony_ci		break;
1378c2ecf20Sopenharmony_ci	case BINARY_PRINT_NUM_DATA:
1388c2ecf20Sopenharmony_ci		printed += color_fprintf(fp, color, " %02x", val);
1398c2ecf20Sopenharmony_ci		break;
1408c2ecf20Sopenharmony_ci	case BINARY_PRINT_NUM_PAD:
1418c2ecf20Sopenharmony_ci		printed += color_fprintf(fp, color, "   ");
1428c2ecf20Sopenharmony_ci		break;
1438c2ecf20Sopenharmony_ci	case BINARY_PRINT_SEP:
1448c2ecf20Sopenharmony_ci		printed += color_fprintf(fp, color, "  ");
1458c2ecf20Sopenharmony_ci		break;
1468c2ecf20Sopenharmony_ci	case BINARY_PRINT_CHAR_DATA:
1478c2ecf20Sopenharmony_ci		printed += color_fprintf(fp, color, "%c",
1488c2ecf20Sopenharmony_ci			      isprint(ch) && isascii(ch) ? ch : '.');
1498c2ecf20Sopenharmony_ci		break;
1508c2ecf20Sopenharmony_ci	case BINARY_PRINT_CHAR_PAD:
1518c2ecf20Sopenharmony_ci		printed += color_fprintf(fp, color, " ");
1528c2ecf20Sopenharmony_ci		break;
1538c2ecf20Sopenharmony_ci	case BINARY_PRINT_LINE_END:
1548c2ecf20Sopenharmony_ci		printed += color_fprintf(fp, color, "\n");
1558c2ecf20Sopenharmony_ci		break;
1568c2ecf20Sopenharmony_ci	case BINARY_PRINT_DATA_END:
1578c2ecf20Sopenharmony_ci		printed += fprintf(fp, "\n");
1588c2ecf20Sopenharmony_ci		break;
1598c2ecf20Sopenharmony_ci	default:
1608c2ecf20Sopenharmony_ci		break;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return printed;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_civoid trace_event(union perf_event *event)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	unsigned char *raw_event = (void *)event;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (!dump_trace)
1718c2ecf20Sopenharmony_ci		return;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	print_binary(raw_event, event->header.size, 16,
1748c2ecf20Sopenharmony_ci		     trace_event_printer, event);
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic struct sublevel_option debug_opts[] = {
1788c2ecf20Sopenharmony_ci	{ .name = "verbose",		.value_ptr = &verbose },
1798c2ecf20Sopenharmony_ci	{ .name = "ordered-events",	.value_ptr = &debug_ordered_events},
1808c2ecf20Sopenharmony_ci	{ .name = "stderr",		.value_ptr = &redirect_to_stderr},
1818c2ecf20Sopenharmony_ci	{ .name = "data-convert",	.value_ptr = &debug_data_convert },
1828c2ecf20Sopenharmony_ci	{ .name = "perf-event-open",	.value_ptr = &debug_peo_args },
1838c2ecf20Sopenharmony_ci	{ .name = NULL, }
1848c2ecf20Sopenharmony_ci};
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ciint perf_debug_option(const char *str)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	int ret;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	ret = perf_parse_sublevel_options(str, debug_opts);
1918c2ecf20Sopenharmony_ci	if (ret)
1928c2ecf20Sopenharmony_ci		return ret;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/* Allow only verbose value in range (0, 10), otherwise set 0. */
1958c2ecf20Sopenharmony_ci	verbose = (verbose < 0) || (verbose > 10) ? 0 : verbose;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return 0;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ciint perf_quiet_option(void)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	struct sublevel_option *opt = &debug_opts[0];
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* disable all debug messages */
2058c2ecf20Sopenharmony_ci	while (opt->name) {
2068c2ecf20Sopenharmony_ci		*opt->value_ptr = -1;
2078c2ecf20Sopenharmony_ci		opt++;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	/* For debug variables that are used as bool types, set to 0. */
2118c2ecf20Sopenharmony_ci	redirect_to_stderr = 0;
2128c2ecf20Sopenharmony_ci	debug_peo_args = 0;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return 0;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci#define DEBUG_WRAPPER(__n, __l)				\
2188c2ecf20Sopenharmony_cistatic int pr_ ## __n ## _wrapper(const char *fmt, ...)	\
2198c2ecf20Sopenharmony_ci{							\
2208c2ecf20Sopenharmony_ci	va_list args;					\
2218c2ecf20Sopenharmony_ci	int ret;					\
2228c2ecf20Sopenharmony_ci							\
2238c2ecf20Sopenharmony_ci	va_start(args, fmt);				\
2248c2ecf20Sopenharmony_ci	ret = veprintf(__l, verbose, fmt, args);	\
2258c2ecf20Sopenharmony_ci	va_end(args);					\
2268c2ecf20Sopenharmony_ci	return ret;					\
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ciDEBUG_WRAPPER(warning, 0);
2308c2ecf20Sopenharmony_ciDEBUG_WRAPPER(debug, 1);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_civoid perf_debug_setup(void)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci/* Obtain a backtrace and print it to stdout. */
2388c2ecf20Sopenharmony_ci#ifdef HAVE_BACKTRACE_SUPPORT
2398c2ecf20Sopenharmony_civoid dump_stack(void)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	void *array[16];
2428c2ecf20Sopenharmony_ci	size_t size = backtrace(array, ARRAY_SIZE(array));
2438c2ecf20Sopenharmony_ci	char **strings = backtrace_symbols(array, size);
2448c2ecf20Sopenharmony_ci	size_t i;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	printf("Obtained %zd stack frames.\n", size);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++)
2498c2ecf20Sopenharmony_ci		printf("%s\n", strings[i]);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	free(strings);
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci#else
2548c2ecf20Sopenharmony_civoid dump_stack(void) {}
2558c2ecf20Sopenharmony_ci#endif
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_civoid sighandler_dump_stack(int sig)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	psignal(sig, "perf");
2608c2ecf20Sopenharmony_ci	dump_stack();
2618c2ecf20Sopenharmony_ci	signal(sig, SIG_DFL);
2628c2ecf20Sopenharmony_ci	raise(sig);
2638c2ecf20Sopenharmony_ci}
264