12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
253af9284SAdrian Hunter /*
353af9284SAdrian Hunter  * intel_pt_log.c: Intel Processor Trace support
453af9284SAdrian Hunter  * Copyright (c) 2013-2014, Intel Corporation.
553af9284SAdrian Hunter  */
653af9284SAdrian Hunter 
753af9284SAdrian Hunter #include <stdio.h>
865aee81aSAdrian Hunter #include <stdlib.h>
953af9284SAdrian Hunter #include <stdint.h>
1053af9284SAdrian Hunter #include <inttypes.h>
1153af9284SAdrian Hunter #include <stdarg.h>
1253af9284SAdrian Hunter #include <stdbool.h>
1353af9284SAdrian Hunter #include <string.h>
1453af9284SAdrian Hunter 
1565aee81aSAdrian Hunter #include <linux/zalloc.h>
1665aee81aSAdrian Hunter #include <linux/kernel.h>
1765aee81aSAdrian Hunter 
1853af9284SAdrian Hunter #include "intel-pt-log.h"
1953af9284SAdrian Hunter #include "intel-pt-insn-decoder.h"
2053af9284SAdrian Hunter 
2153af9284SAdrian Hunter #include "intel-pt-pkt-decoder.h"
2253af9284SAdrian Hunter 
2353af9284SAdrian Hunter #define MAX_LOG_NAME 256
2453af9284SAdrian Hunter 
2565aee81aSAdrian Hunter #define DFLT_BUF_SZ	(16 * 1024)
2665aee81aSAdrian Hunter 
2765aee81aSAdrian Hunter struct log_buf {
2865aee81aSAdrian Hunter 	char			*buf;
2965aee81aSAdrian Hunter 	size_t			buf_sz;
3065aee81aSAdrian Hunter 	size_t			head;
3165aee81aSAdrian Hunter 	bool			wrapped;
3265aee81aSAdrian Hunter 	FILE			*backend;
3365aee81aSAdrian Hunter };
3465aee81aSAdrian Hunter 
3553af9284SAdrian Hunter static FILE *f;
3653af9284SAdrian Hunter static char log_name[MAX_LOG_NAME];
37116f349cSAdrian Hunter bool intel_pt_enable_logging;
3865aee81aSAdrian Hunter static bool intel_pt_dump_log_on_error;
3965aee81aSAdrian Hunter static unsigned int intel_pt_log_on_error_size;
4065aee81aSAdrian Hunter static struct log_buf log_buf;
4153af9284SAdrian Hunter 
intel_pt_log_fp(void)4293f8be27SAdrian Hunter void *intel_pt_log_fp(void)
4393f8be27SAdrian Hunter {
4493f8be27SAdrian Hunter 	return f;
4593f8be27SAdrian Hunter }
4693f8be27SAdrian Hunter 
intel_pt_log_enable(bool dump_log_on_error,unsigned int log_on_error_size)4765aee81aSAdrian Hunter void intel_pt_log_enable(bool dump_log_on_error, unsigned int log_on_error_size)
4853af9284SAdrian Hunter {
49116f349cSAdrian Hunter 	intel_pt_enable_logging = true;
5065aee81aSAdrian Hunter 	intel_pt_dump_log_on_error = dump_log_on_error;
5165aee81aSAdrian Hunter 	intel_pt_log_on_error_size = log_on_error_size;
5253af9284SAdrian Hunter }
5353af9284SAdrian Hunter 
intel_pt_log_disable(void)5453af9284SAdrian Hunter void intel_pt_log_disable(void)
5553af9284SAdrian Hunter {
5653af9284SAdrian Hunter 	if (f)
5753af9284SAdrian Hunter 		fflush(f);
58116f349cSAdrian Hunter 	intel_pt_enable_logging = false;
5953af9284SAdrian Hunter }
6053af9284SAdrian Hunter 
intel_pt_log_set_name(const char * name)6153af9284SAdrian Hunter void intel_pt_log_set_name(const char *name)
6253af9284SAdrian Hunter {
6353af9284SAdrian Hunter 	strncpy(log_name, name, MAX_LOG_NAME - 5);
6453af9284SAdrian Hunter 	strcat(log_name, ".log");
6553af9284SAdrian Hunter }
6653af9284SAdrian Hunter 
intel_pt_print_data(const unsigned char * buf,int len,uint64_t pos,int indent)6753af9284SAdrian Hunter static void intel_pt_print_data(const unsigned char *buf, int len, uint64_t pos,
6853af9284SAdrian Hunter 				int indent)
6953af9284SAdrian Hunter {
7053af9284SAdrian Hunter 	int i;
7153af9284SAdrian Hunter 
7253af9284SAdrian Hunter 	for (i = 0; i < indent; i++)
7353af9284SAdrian Hunter 		fprintf(f, " ");
7453af9284SAdrian Hunter 
7553af9284SAdrian Hunter 	fprintf(f, "  %08" PRIx64 ": ", pos);
7653af9284SAdrian Hunter 	for (i = 0; i < len; i++)
7753af9284SAdrian Hunter 		fprintf(f, " %02x", buf[i]);
7853af9284SAdrian Hunter 	for (; i < 16; i++)
7953af9284SAdrian Hunter 		fprintf(f, "   ");
8053af9284SAdrian Hunter 	fprintf(f, " ");
8153af9284SAdrian Hunter }
8253af9284SAdrian Hunter 
intel_pt_print_no_data(uint64_t pos,int indent)8353af9284SAdrian Hunter static void intel_pt_print_no_data(uint64_t pos, int indent)
8453af9284SAdrian Hunter {
8553af9284SAdrian Hunter 	int i;
8653af9284SAdrian Hunter 
8753af9284SAdrian Hunter 	for (i = 0; i < indent; i++)
8853af9284SAdrian Hunter 		fprintf(f, " ");
8953af9284SAdrian Hunter 
9053af9284SAdrian Hunter 	fprintf(f, "  %08" PRIx64 ": ", pos);
9153af9284SAdrian Hunter 	for (i = 0; i < 16; i++)
9253af9284SAdrian Hunter 		fprintf(f, "   ");
9353af9284SAdrian Hunter 	fprintf(f, " ");
9453af9284SAdrian Hunter }
9553af9284SAdrian Hunter 
log_buf__write(void * cookie,const char * buf,size_t size)9665aee81aSAdrian Hunter static ssize_t log_buf__write(void *cookie, const char *buf, size_t size)
9765aee81aSAdrian Hunter {
9865aee81aSAdrian Hunter 	struct log_buf *b = cookie;
9965aee81aSAdrian Hunter 	size_t sz = size;
10065aee81aSAdrian Hunter 
10165aee81aSAdrian Hunter 	if (!b->buf)
10265aee81aSAdrian Hunter 		return size;
10365aee81aSAdrian Hunter 
10465aee81aSAdrian Hunter 	while (sz) {
10565aee81aSAdrian Hunter 		size_t space = b->buf_sz - b->head;
10665aee81aSAdrian Hunter 		size_t n = min(space, sz);
10765aee81aSAdrian Hunter 
10865aee81aSAdrian Hunter 		memcpy(b->buf + b->head, buf, n);
10965aee81aSAdrian Hunter 		sz -= n;
11065aee81aSAdrian Hunter 		buf += n;
11165aee81aSAdrian Hunter 		b->head += n;
11265aee81aSAdrian Hunter 		if (sz && b->head >= b->buf_sz) {
11365aee81aSAdrian Hunter 			b->head = 0;
11465aee81aSAdrian Hunter 			b->wrapped = true;
11565aee81aSAdrian Hunter 		}
11665aee81aSAdrian Hunter 	}
11765aee81aSAdrian Hunter 	return size;
11865aee81aSAdrian Hunter }
11965aee81aSAdrian Hunter 
log_buf__close(void * cookie)12065aee81aSAdrian Hunter static int log_buf__close(void *cookie)
12165aee81aSAdrian Hunter {
12265aee81aSAdrian Hunter 	struct log_buf *b = cookie;
12365aee81aSAdrian Hunter 
12465aee81aSAdrian Hunter 	zfree(&b->buf);
12565aee81aSAdrian Hunter 	return 0;
12665aee81aSAdrian Hunter }
12765aee81aSAdrian Hunter 
log_buf__open(struct log_buf * b,FILE * backend,unsigned int sz)12865aee81aSAdrian Hunter static FILE *log_buf__open(struct log_buf *b, FILE *backend, unsigned int sz)
12965aee81aSAdrian Hunter {
13065aee81aSAdrian Hunter 	cookie_io_functions_t fns = {
13165aee81aSAdrian Hunter 		.write = log_buf__write,
13265aee81aSAdrian Hunter 		.close = log_buf__close,
13365aee81aSAdrian Hunter 	};
13465aee81aSAdrian Hunter 	FILE *file;
13565aee81aSAdrian Hunter 
13665aee81aSAdrian Hunter 	memset(b, 0, sizeof(*b));
13765aee81aSAdrian Hunter 	b->buf_sz = sz;
13865aee81aSAdrian Hunter 	b->buf = malloc(b->buf_sz);
13965aee81aSAdrian Hunter 	b->backend = backend;
14065aee81aSAdrian Hunter 	file = fopencookie(b, "a", fns);
14165aee81aSAdrian Hunter 	if (!file)
14265aee81aSAdrian Hunter 		zfree(&b->buf);
14365aee81aSAdrian Hunter 	return file;
14465aee81aSAdrian Hunter }
14565aee81aSAdrian Hunter 
remove_first_line(const char ** p,size_t * n)146*3b7ae354SAdrian Hunter static bool remove_first_line(const char **p, size_t *n)
147*3b7ae354SAdrian Hunter {
148*3b7ae354SAdrian Hunter 	for (; *n && **p != '\n'; ++*p, --*n)
149*3b7ae354SAdrian Hunter 		;
150*3b7ae354SAdrian Hunter 	if (*n) {
151*3b7ae354SAdrian Hunter 		*p += 1;
152*3b7ae354SAdrian Hunter 		*n -= 1;
153*3b7ae354SAdrian Hunter 		return true;
154*3b7ae354SAdrian Hunter 	}
155*3b7ae354SAdrian Hunter 	return false;
156*3b7ae354SAdrian Hunter }
157*3b7ae354SAdrian Hunter 
write_lines(const char * p,size_t n,FILE * fp,bool * remove_first)158*3b7ae354SAdrian Hunter static void write_lines(const char *p, size_t n, FILE *fp, bool *remove_first)
159*3b7ae354SAdrian Hunter {
160*3b7ae354SAdrian Hunter 	if (*remove_first)
161*3b7ae354SAdrian Hunter 		*remove_first = !remove_first_line(&p, &n);
162*3b7ae354SAdrian Hunter 	fwrite(p, n, 1, fp);
163*3b7ae354SAdrian Hunter }
164*3b7ae354SAdrian Hunter 
log_buf__dump(struct log_buf * b)16565aee81aSAdrian Hunter static void log_buf__dump(struct log_buf *b)
16665aee81aSAdrian Hunter {
167*3b7ae354SAdrian Hunter 	bool remove_first = false;
168*3b7ae354SAdrian Hunter 
16965aee81aSAdrian Hunter 	if (!b->buf)
17065aee81aSAdrian Hunter 		return;
17165aee81aSAdrian Hunter 
172*3b7ae354SAdrian Hunter 	fflush(f); /* Could update b->head and b->wrapped */
173*3b7ae354SAdrian Hunter 	fprintf(b->backend, "Dumping debug log buffer\n");
174*3b7ae354SAdrian Hunter 	if (b->wrapped) {
175*3b7ae354SAdrian Hunter 		remove_first = true;
176*3b7ae354SAdrian Hunter 		write_lines(b->buf + b->head, b->buf_sz - b->head, b->backend, &remove_first);
177*3b7ae354SAdrian Hunter 	}
178*3b7ae354SAdrian Hunter 	write_lines(b->buf, b->head, b->backend, &remove_first);
17965aee81aSAdrian Hunter 	fprintf(b->backend, "End of debug log buffer dump\n");
18065aee81aSAdrian Hunter 
18165aee81aSAdrian Hunter 	b->head = 0;
18265aee81aSAdrian Hunter 	b->wrapped = false;
18365aee81aSAdrian Hunter }
18465aee81aSAdrian Hunter 
intel_pt_log_dump_buf(void)18565aee81aSAdrian Hunter void intel_pt_log_dump_buf(void)
18665aee81aSAdrian Hunter {
18765aee81aSAdrian Hunter 	log_buf__dump(&log_buf);
18865aee81aSAdrian Hunter }
18965aee81aSAdrian Hunter 
intel_pt_log_open(void)19053af9284SAdrian Hunter static int intel_pt_log_open(void)
19153af9284SAdrian Hunter {
192116f349cSAdrian Hunter 	if (!intel_pt_enable_logging)
19353af9284SAdrian Hunter 		return -1;
19453af9284SAdrian Hunter 
19553af9284SAdrian Hunter 	if (f)
19653af9284SAdrian Hunter 		return 0;
19753af9284SAdrian Hunter 
198624ff63aSAdrian Hunter 	if (log_name[0])
19953af9284SAdrian Hunter 		f = fopen(log_name, "w+");
200624ff63aSAdrian Hunter 	else
201624ff63aSAdrian Hunter 		f = stdout;
20265aee81aSAdrian Hunter 	if (f && intel_pt_dump_log_on_error)
20365aee81aSAdrian Hunter 		f = log_buf__open(&log_buf, f, intel_pt_log_on_error_size);
20453af9284SAdrian Hunter 	if (!f) {
205116f349cSAdrian Hunter 		intel_pt_enable_logging = false;
20653af9284SAdrian Hunter 		return -1;
20753af9284SAdrian Hunter 	}
20853af9284SAdrian Hunter 
20953af9284SAdrian Hunter 	return 0;
21053af9284SAdrian Hunter }
21153af9284SAdrian Hunter 
__intel_pt_log_packet(const struct intel_pt_pkt * packet,int pkt_len,uint64_t pos,const unsigned char * buf)212116f349cSAdrian Hunter void __intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len,
21353af9284SAdrian Hunter 			   uint64_t pos, const unsigned char *buf)
21453af9284SAdrian Hunter {
21553af9284SAdrian Hunter 	char desc[INTEL_PT_PKT_DESC_MAX];
21653af9284SAdrian Hunter 
21753af9284SAdrian Hunter 	if (intel_pt_log_open())
21853af9284SAdrian Hunter 		return;
21953af9284SAdrian Hunter 
22053af9284SAdrian Hunter 	intel_pt_print_data(buf, pkt_len, pos, 0);
22153af9284SAdrian Hunter 	intel_pt_pkt_desc(packet, desc, INTEL_PT_PKT_DESC_MAX);
22253af9284SAdrian Hunter 	fprintf(f, "%s\n", desc);
22353af9284SAdrian Hunter }
22453af9284SAdrian Hunter 
__intel_pt_log_insn(struct intel_pt_insn * intel_pt_insn,uint64_t ip)225116f349cSAdrian Hunter void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip)
22653af9284SAdrian Hunter {
22753af9284SAdrian Hunter 	char desc[INTEL_PT_INSN_DESC_MAX];
22853af9284SAdrian Hunter 	size_t len = intel_pt_insn->length;
22953af9284SAdrian Hunter 
23053af9284SAdrian Hunter 	if (intel_pt_log_open())
23153af9284SAdrian Hunter 		return;
23253af9284SAdrian Hunter 
23332f98aabSAdrian Hunter 	if (len > INTEL_PT_INSN_BUF_SZ)
23432f98aabSAdrian Hunter 		len = INTEL_PT_INSN_BUF_SZ;
23553af9284SAdrian Hunter 	intel_pt_print_data(intel_pt_insn->buf, len, ip, 8);
23653af9284SAdrian Hunter 	if (intel_pt_insn_desc(intel_pt_insn, desc, INTEL_PT_INSN_DESC_MAX) > 0)
23753af9284SAdrian Hunter 		fprintf(f, "%s\n", desc);
23853af9284SAdrian Hunter 	else
23953af9284SAdrian Hunter 		fprintf(f, "Bad instruction!\n");
24053af9284SAdrian Hunter }
24153af9284SAdrian Hunter 
__intel_pt_log_insn_no_data(struct intel_pt_insn * intel_pt_insn,uint64_t ip)242116f349cSAdrian Hunter void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn,
243116f349cSAdrian Hunter 				 uint64_t ip)
24453af9284SAdrian Hunter {
24553af9284SAdrian Hunter 	char desc[INTEL_PT_INSN_DESC_MAX];
24653af9284SAdrian Hunter 
24753af9284SAdrian Hunter 	if (intel_pt_log_open())
24853af9284SAdrian Hunter 		return;
24953af9284SAdrian Hunter 
25053af9284SAdrian Hunter 	intel_pt_print_no_data(ip, 8);
25153af9284SAdrian Hunter 	if (intel_pt_insn_desc(intel_pt_insn, desc, INTEL_PT_INSN_DESC_MAX) > 0)
25253af9284SAdrian Hunter 		fprintf(f, "%s\n", desc);
25353af9284SAdrian Hunter 	else
25453af9284SAdrian Hunter 		fprintf(f, "Bad instruction!\n");
25553af9284SAdrian Hunter }
25653af9284SAdrian Hunter 
__intel_pt_log(const char * fmt,...)257116f349cSAdrian Hunter void __intel_pt_log(const char *fmt, ...)
25853af9284SAdrian Hunter {
25953af9284SAdrian Hunter 	va_list args;
26053af9284SAdrian Hunter 
26153af9284SAdrian Hunter 	if (intel_pt_log_open())
26253af9284SAdrian Hunter 		return;
26353af9284SAdrian Hunter 
26453af9284SAdrian Hunter 	va_start(args, fmt);
26553af9284SAdrian Hunter 	vfprintf(f, fmt, args);
26653af9284SAdrian Hunter 	va_end(args);
26753af9284SAdrian Hunter }
268