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