xref: /freebsd/contrib/processor-trace/libipt/src/pt_insn.c (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
1 /*
2  * Copyright (c) 2016-2019, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "pt_insn.h"
30 #include "pt_ild.h"
31 #include "pt_image.h"
32 #include "pt_compiler.h"
33 
34 #include "intel-pt.h"
35 
36 
37 int pt_insn_changes_cpl(const struct pt_insn *insn,
38 			const struct pt_insn_ext *iext)
39 {
40 	(void) insn;
41 
42 	if (!iext)
43 		return 0;
44 
45 	switch (iext->iclass) {
46 	default:
47 		return 0;
48 
49 	case PTI_INST_INT:
50 	case PTI_INST_INT3:
51 	case PTI_INST_INT1:
52 	case PTI_INST_INTO:
53 	case PTI_INST_IRET:
54 	case PTI_INST_SYSCALL:
55 	case PTI_INST_SYSENTER:
56 	case PTI_INST_SYSEXIT:
57 	case PTI_INST_SYSRET:
58 		return 1;
59 	}
60 }
61 
62 int pt_insn_changes_cr3(const struct pt_insn *insn,
63 			const struct pt_insn_ext *iext)
64 {
65 	(void) insn;
66 
67 	if (!iext)
68 		return 0;
69 
70 	switch (iext->iclass) {
71 	default:
72 		return 0;
73 
74 	case PTI_INST_MOV_CR3:
75 		return 1;
76 	}
77 }
78 
79 int pt_insn_is_branch(const struct pt_insn *insn,
80 		      const struct pt_insn_ext *iext)
81 {
82 	(void) iext;
83 
84 	if (!insn)
85 		return 0;
86 
87 	switch (insn->iclass) {
88 	default:
89 		return 0;
90 
91 	case ptic_call:
92 	case ptic_return:
93 	case ptic_jump:
94 	case ptic_cond_jump:
95 	case ptic_far_call:
96 	case ptic_far_return:
97 	case ptic_far_jump:
98 		return 1;
99 	}
100 }
101 
102 int pt_insn_is_far_branch(const struct pt_insn *insn,
103 			  const struct pt_insn_ext *iext)
104 {
105 	(void) iext;
106 
107 	if (!insn)
108 		return 0;
109 
110 	switch (insn->iclass) {
111 	default:
112 		return 0;
113 
114 	case ptic_far_call:
115 	case ptic_far_return:
116 	case ptic_far_jump:
117 		return 1;
118 	}
119 }
120 
121 int pt_insn_binds_to_pip(const struct pt_insn *insn,
122 			 const struct pt_insn_ext *iext)
123 {
124 	if (!iext)
125 		return 0;
126 
127 	switch (iext->iclass) {
128 	default:
129 		return pt_insn_is_far_branch(insn, iext);
130 
131 	case PTI_INST_MOV_CR3:
132 	case PTI_INST_VMLAUNCH:
133 	case PTI_INST_VMRESUME:
134 		return 1;
135 	}
136 }
137 
138 int pt_insn_binds_to_vmcs(const struct pt_insn *insn,
139 			  const struct pt_insn_ext *iext)
140 {
141 	if (!iext)
142 		return 0;
143 
144 	switch (iext->iclass) {
145 	default:
146 		return pt_insn_is_far_branch(insn, iext);
147 
148 	case PTI_INST_VMPTRLD:
149 	case PTI_INST_VMLAUNCH:
150 	case PTI_INST_VMRESUME:
151 		return 1;
152 	}
153 }
154 
155 int pt_insn_is_ptwrite(const struct pt_insn *insn,
156 		       const struct pt_insn_ext *iext)
157 {
158 	(void) iext;
159 
160 	if (!insn)
161 		return 0;
162 
163 	switch (insn->iclass) {
164 	default:
165 		return 0;
166 
167 	case ptic_ptwrite:
168 		return 1;
169 	}
170 }
171 
172 int pt_insn_next_ip(uint64_t *pip, const struct pt_insn *insn,
173 		    const struct pt_insn_ext *iext)
174 {
175 	uint64_t ip;
176 
177 	if (!insn || !iext)
178 		return -pte_internal;
179 
180 	ip = insn->ip + insn->size;
181 
182 	switch (insn->iclass) {
183 	case ptic_ptwrite:
184 	case ptic_other:
185 		break;
186 
187 	case ptic_call:
188 	case ptic_jump:
189 		if (iext->variant.branch.is_direct) {
190 			ip += (uint64_t) (int64_t)
191 				iext->variant.branch.displacement;
192 			break;
193 		}
194 
195 		fallthrough;
196 	default:
197 		return -pte_bad_query;
198 
199 	case ptic_error:
200 		return -pte_bad_insn;
201 	}
202 
203 	if (pip)
204 		*pip = ip;
205 
206 	return 0;
207 }
208 
209 /* Retry decoding an instruction after a preceding decode error.
210  *
211  * Instruction length decode typically fails due to 'not enough
212  * bytes'.
213  *
214  * This may be caused by partial updates of text sections
215  * represented via new image sections overlapping the original
216  * text section's image section.  We stop reading memory at the
217  * end of the section so we do not read the full instruction if
218  * parts of it have been overwritten by the update.
219  *
220  * Try to read the remaining bytes and decode the instruction again.  If we
221  * succeed, set @insn->truncated to indicate that the instruction is truncated
222  * in @insn->isid.
223  *
224  * Returns zero on success, a negative error code otherwise.
225  * Returns -pte_bad_insn if the instruction could not be decoded.
226  */
227 static int pt_insn_decode_retry(struct pt_insn *insn, struct pt_insn_ext *iext,
228 				struct pt_image *image,
229 				const struct pt_asid *asid)
230 {
231 	int size, errcode, isid;
232 	uint8_t isize, remaining;
233 
234 	if (!insn)
235 		return -pte_internal;
236 
237 	isize = insn->size;
238 	remaining = sizeof(insn->raw) - isize;
239 
240 	/* We failed for real if we already read the maximum number of bytes for
241 	 * an instruction.
242 	 */
243 	if (!remaining)
244 		return -pte_bad_insn;
245 
246 	/* Read the remaining bytes from the image. */
247 	size = pt_image_read(image, &isid, &insn->raw[isize], remaining, asid,
248 			     insn->ip + isize);
249 	if (size <= 0) {
250 		/* We should have gotten an error if we were not able to read at
251 		 * least one byte.  Check this to guarantee termination.
252 		 */
253 		if (!size)
254 			return -pte_internal;
255 
256 		/* Preserve the original error if there are no more bytes. */
257 		if (size == -pte_nomap)
258 			size = -pte_bad_insn;
259 
260 		return size;
261 	}
262 
263 	/* Add the newly read bytes to the instruction's size. */
264 	insn->size += (uint8_t) size;
265 
266 	/* Store the new size to avoid infinite recursion in case instruction
267 	 * decode fails after length decode, which would set @insn->size to the
268 	 * actual length.
269 	 */
270 	size = insn->size;
271 
272 	/* Try to decode the instruction again.
273 	 *
274 	 * If we fail again, we recursively retry again until we either fail to
275 	 * read more bytes or reach the maximum number of bytes for an
276 	 * instruction.
277 	 */
278 	errcode = pt_ild_decode(insn, iext);
279 	if (errcode < 0) {
280 		if (errcode != -pte_bad_insn)
281 			return errcode;
282 
283 		/* If instruction length decode already determined the size,
284 		 * there's no point in reading more bytes.
285 		 */
286 		if (insn->size != (uint8_t) size)
287 			return errcode;
288 
289 		return pt_insn_decode_retry(insn, iext, image, asid);
290 	}
291 
292 	/* We succeeded this time, so the instruction crosses image section
293 	 * boundaries.
294 	 *
295 	 * This poses the question which isid to use for the instruction.
296 	 *
297 	 * To reconstruct exactly this instruction at a later time, we'd need to
298 	 * store all isids involved together with the number of bytes read for
299 	 * each isid.  Since @insn already provides the exact bytes for this
300 	 * instruction, we assume that the isid will be used solely for source
301 	 * correlation.  In this case, it should refer to the first byte of the
302 	 * instruction - as it already does.
303 	 */
304 	insn->truncated = 1;
305 
306 	return errcode;
307 }
308 
309 int pt_insn_decode(struct pt_insn *insn, struct pt_insn_ext *iext,
310 		   struct pt_image *image, const struct pt_asid *asid)
311 {
312 	int size, errcode;
313 
314 	if (!insn)
315 		return -pte_internal;
316 
317 	/* Read the memory at the current IP in the current address space. */
318 	size = pt_image_read(image, &insn->isid, insn->raw, sizeof(insn->raw),
319 			     asid, insn->ip);
320 	if (size < 0)
321 		return size;
322 
323 	/* We initialize @insn->size to the maximal possible size.  It will be
324 	 * set to the actual size during instruction decode.
325 	 */
326 	insn->size = (uint8_t) size;
327 
328 	errcode = pt_ild_decode(insn, iext);
329 	if (errcode < 0) {
330 		if (errcode != -pte_bad_insn)
331 			return errcode;
332 
333 		/* If instruction length decode already determined the size,
334 		 * there's no point in reading more bytes.
335 		 */
336 		if (insn->size != (uint8_t) size)
337 			return errcode;
338 
339 		return pt_insn_decode_retry(insn, iext, image, asid);
340 	}
341 
342 	return errcode;
343 }
344 
345 int pt_insn_range_is_contiguous(uint64_t begin, uint64_t end,
346 				enum pt_exec_mode mode, struct pt_image *image,
347 				const struct pt_asid *asid, size_t steps)
348 {
349 	struct pt_insn_ext iext;
350 	struct pt_insn insn;
351 
352 	memset(&insn, 0, sizeof(insn));
353 
354 	insn.mode = mode;
355 	insn.ip = begin;
356 
357 	while (insn.ip != end) {
358 		int errcode;
359 
360 		if (!steps--)
361 			return 0;
362 
363 		errcode = pt_insn_decode(&insn, &iext, image, asid);
364 		if (errcode < 0)
365 			return errcode;
366 
367 		errcode = pt_insn_next_ip(&insn.ip, &insn, &iext);
368 		if (errcode < 0)
369 			return errcode;
370 	}
371 
372 	return 1;
373 }
374