1 /*
2  * intel_pt_log.c: Intel Processor Trace support
3  * Copyright (c) 2013-2014, Intel Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  */
15 
16 #include <stdio.h>
17 #include <stdint.h>
18 #include <inttypes.h>
19 #include <stdarg.h>
20 #include <stdbool.h>
21 #include <string.h>
22 
23 #include "intel-pt-log.h"
24 #include "intel-pt-insn-decoder.h"
25 
26 #include "intel-pt-pkt-decoder.h"
27 
28 #define MAX_LOG_NAME 256
29 
30 static FILE *f;
31 static char log_name[MAX_LOG_NAME];
32 bool intel_pt_enable_logging;
33 
34 void *intel_pt_log_fp(void)
35 {
36 	return f;
37 }
38 
39 void intel_pt_log_enable(void)
40 {
41 	intel_pt_enable_logging = true;
42 }
43 
44 void intel_pt_log_disable(void)
45 {
46 	if (f)
47 		fflush(f);
48 	intel_pt_enable_logging = false;
49 }
50 
51 void intel_pt_log_set_name(const char *name)
52 {
53 	strncpy(log_name, name, MAX_LOG_NAME - 5);
54 	strcat(log_name, ".log");
55 }
56 
57 static void intel_pt_print_data(const unsigned char *buf, int len, uint64_t pos,
58 				int indent)
59 {
60 	int i;
61 
62 	for (i = 0; i < indent; i++)
63 		fprintf(f, " ");
64 
65 	fprintf(f, "  %08" PRIx64 ": ", pos);
66 	for (i = 0; i < len; i++)
67 		fprintf(f, " %02x", buf[i]);
68 	for (; i < 16; i++)
69 		fprintf(f, "   ");
70 	fprintf(f, " ");
71 }
72 
73 static void intel_pt_print_no_data(uint64_t pos, int indent)
74 {
75 	int i;
76 
77 	for (i = 0; i < indent; i++)
78 		fprintf(f, " ");
79 
80 	fprintf(f, "  %08" PRIx64 ": ", pos);
81 	for (i = 0; i < 16; i++)
82 		fprintf(f, "   ");
83 	fprintf(f, " ");
84 }
85 
86 static int intel_pt_log_open(void)
87 {
88 	if (!intel_pt_enable_logging)
89 		return -1;
90 
91 	if (f)
92 		return 0;
93 
94 	if (!log_name[0])
95 		return -1;
96 
97 	f = fopen(log_name, "w+");
98 	if (!f) {
99 		intel_pt_enable_logging = false;
100 		return -1;
101 	}
102 
103 	return 0;
104 }
105 
106 void __intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len,
107 			   uint64_t pos, const unsigned char *buf)
108 {
109 	char desc[INTEL_PT_PKT_DESC_MAX];
110 
111 	if (intel_pt_log_open())
112 		return;
113 
114 	intel_pt_print_data(buf, pkt_len, pos, 0);
115 	intel_pt_pkt_desc(packet, desc, INTEL_PT_PKT_DESC_MAX);
116 	fprintf(f, "%s\n", desc);
117 }
118 
119 void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip)
120 {
121 	char desc[INTEL_PT_INSN_DESC_MAX];
122 	size_t len = intel_pt_insn->length;
123 
124 	if (intel_pt_log_open())
125 		return;
126 
127 	if (len > INTEL_PT_INSN_BUF_SZ)
128 		len = INTEL_PT_INSN_BUF_SZ;
129 	intel_pt_print_data(intel_pt_insn->buf, len, ip, 8);
130 	if (intel_pt_insn_desc(intel_pt_insn, desc, INTEL_PT_INSN_DESC_MAX) > 0)
131 		fprintf(f, "%s\n", desc);
132 	else
133 		fprintf(f, "Bad instruction!\n");
134 }
135 
136 void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn,
137 				 uint64_t ip)
138 {
139 	char desc[INTEL_PT_INSN_DESC_MAX];
140 
141 	if (intel_pt_log_open())
142 		return;
143 
144 	intel_pt_print_no_data(ip, 8);
145 	if (intel_pt_insn_desc(intel_pt_insn, desc, INTEL_PT_INSN_DESC_MAX) > 0)
146 		fprintf(f, "%s\n", desc);
147 	else
148 		fprintf(f, "Bad instruction!\n");
149 }
150 
151 void __intel_pt_log(const char *fmt, ...)
152 {
153 	va_list args;
154 
155 	if (intel_pt_log_open())
156 		return;
157 
158 	va_start(args, fmt);
159 	vfprintf(f, fmt, args);
160 	va_end(args);
161 }
162