xref: /freebsd/contrib/processor-trace/libipt/src/pt_image.c (revision 405c3050f102b8c74782f0366c8ead927bd07b68)
1 /*
2  * Copyright (c) 2013-2018, 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_image.h"
30 #include "pt_section.h"
31 #include "pt_asid.h"
32 #include "pt_image_section_cache.h"
33 
34 #include <stdlib.h>
35 #include <string.h>
36 
37 
38 static char *dupstr(const char *str)
39 {
40 	char *dup;
41 	size_t len;
42 
43 	if (!str)
44 		return NULL;
45 
46 	len = strlen(str);
47 	dup = malloc(len + 1);
48 	if (!dup)
49 		return NULL;
50 
51 	return strcpy(dup, str);
52 }
53 
54 static struct pt_section_list *pt_mk_section_list(struct pt_section *section,
55 						  const struct pt_asid *asid,
56 						  uint64_t vaddr,
57 						  uint64_t offset,
58 						  uint64_t size, int isid)
59 {
60 	struct pt_section_list *list;
61 	int errcode;
62 
63 	list = malloc(sizeof(*list));
64 	if (!list)
65 		return NULL;
66 
67 	memset(list, 0, sizeof(*list));
68 
69 	errcode = pt_section_get(section);
70 	if (errcode < 0)
71 		goto out_mem;
72 
73 	pt_msec_init(&list->section, section, asid, vaddr, offset, size);
74 	list->isid = isid;
75 
76 	return list;
77 
78 out_mem:
79 	free(list);
80 	return NULL;
81 }
82 
83 static void pt_section_list_free(struct pt_section_list *list)
84 {
85 	if (!list)
86 		return;
87 
88 	pt_section_put(list->section.section);
89 	pt_msec_fini(&list->section);
90 	free(list);
91 }
92 
93 static void pt_section_list_free_tail(struct pt_section_list *list)
94 {
95 	while (list) {
96 		struct pt_section_list *trash;
97 
98 		trash = list;
99 		list = list->next;
100 
101 		pt_section_list_free(trash);
102 	}
103 }
104 
105 void pt_image_init(struct pt_image *image, const char *name)
106 {
107 	if (!image)
108 		return;
109 
110 	memset(image, 0, sizeof(*image));
111 
112 	image->name = dupstr(name);
113 }
114 
115 void pt_image_fini(struct pt_image *image)
116 {
117 	if (!image)
118 		return;
119 
120 	pt_section_list_free_tail(image->sections);
121 	free(image->name);
122 
123 	memset(image, 0, sizeof(*image));
124 }
125 
126 struct pt_image *pt_image_alloc(const char *name)
127 {
128 	struct pt_image *image;
129 
130 	image = malloc(sizeof(*image));
131 	if (image)
132 		pt_image_init(image, name);
133 
134 	return image;
135 }
136 
137 void pt_image_free(struct pt_image *image)
138 {
139 	pt_image_fini(image);
140 	free(image);
141 }
142 
143 const char *pt_image_name(const struct pt_image *image)
144 {
145 	if (!image)
146 		return NULL;
147 
148 	return image->name;
149 }
150 
151 int pt_image_add(struct pt_image *image, struct pt_section *section,
152 		 const struct pt_asid *asid, uint64_t vaddr, int isid)
153 {
154 	struct pt_section_list **list, *next, *removed, *new;
155 	uint64_t size, begin, end;
156 	int errcode;
157 
158 	if (!image || !section)
159 		return -pte_internal;
160 
161 	size = pt_section_size(section);
162 	begin = vaddr;
163 	end = begin + size;
164 
165 	next = pt_mk_section_list(section, asid, begin, 0ull, size, isid);
166 	if (!next)
167 		return -pte_nomem;
168 
169 	removed = NULL;
170 	errcode = 0;
171 
172 	/* Check for overlaps while we move to the end of the list. */
173 	list = &(image->sections);
174 	while (*list) {
175 		const struct pt_mapped_section *msec;
176 		const struct pt_asid *masid;
177 		struct pt_section_list *current;
178 		struct pt_section *lsec;
179 		uint64_t lbegin, lend, loff;
180 
181 		current = *list;
182 		msec = &current->section;
183 		masid = pt_msec_asid(msec);
184 
185 		errcode = pt_asid_match(masid, asid);
186 		if (errcode < 0)
187 			break;
188 
189 		if (!errcode) {
190 			list = &((*list)->next);
191 			continue;
192 		}
193 
194 		lbegin = pt_msec_begin(msec);
195 		lend = pt_msec_end(msec);
196 
197 		if ((end <= lbegin) || (lend <= begin)) {
198 			list = &((*list)->next);
199 			continue;
200 		}
201 
202 		/* The new section overlaps with @msec's section. */
203 		lsec = pt_msec_section(msec);
204 		loff = pt_msec_offset(msec);
205 
206 		/* We remove @msec and insert new sections for the remaining
207 		 * parts, if any.  Those new sections are not mapped initially
208 		 * and need to be added to the end of the section list.
209 		 */
210 		*list = current->next;
211 
212 		/* Keep a list of removed sections so we can re-add them in case
213 		 * of errors.
214 		 */
215 		current->next = removed;
216 		removed = current;
217 
218 		/* Add a section covering the remaining bytes at the front. */
219 		if (lbegin < begin) {
220 			new = pt_mk_section_list(lsec, masid, lbegin, loff,
221 						 begin - lbegin, current->isid);
222 			if (!new) {
223 				errcode = -pte_nomem;
224 				break;
225 			}
226 
227 			new->next = next;
228 			next = new;
229 		}
230 
231 		/* Add a section covering the remaining bytes at the back. */
232 		if (end < lend) {
233 			new = pt_mk_section_list(lsec, masid, end,
234 						 loff + (end - lbegin),
235 						 lend - end, current->isid);
236 			if (!new) {
237 				errcode = -pte_nomem;
238 				break;
239 			}
240 
241 			new->next = next;
242 			next = new;
243 		}
244 	}
245 
246 	if (errcode < 0) {
247 		pt_section_list_free_tail(next);
248 
249 		/* Re-add removed sections to the tail of the section list. */
250 		for (; *list; list = &((*list)->next))
251 			;
252 
253 		*list = removed;
254 		return errcode;
255 	}
256 
257 	pt_section_list_free_tail(removed);
258 
259 	*list = next;
260 	return 0;
261 }
262 
263 int pt_image_remove(struct pt_image *image, struct pt_section *section,
264 		    const struct pt_asid *asid, uint64_t vaddr)
265 {
266 	struct pt_section_list **list;
267 
268 	if (!image || !section)
269 		return -pte_internal;
270 
271 	for (list = &image->sections; *list; list = &((*list)->next)) {
272 		struct pt_mapped_section *msec;
273 		const struct pt_section *sec;
274 		const struct pt_asid *masid;
275 		struct pt_section_list *trash;
276 		uint64_t begin;
277 		int errcode;
278 
279 		trash = *list;
280 		msec = &trash->section;
281 		masid = pt_msec_asid(msec);
282 
283 		errcode = pt_asid_match(masid, asid);
284 		if (errcode < 0)
285 			return errcode;
286 
287 		if (!errcode)
288 			continue;
289 
290 		begin = pt_msec_begin(msec);
291 		sec = pt_msec_section(msec);
292 		if (sec == section && begin == vaddr) {
293 			*list = trash->next;
294 			pt_section_list_free(trash);
295 
296 			return 0;
297 		}
298 	}
299 
300 	return -pte_bad_image;
301 }
302 
303 int pt_image_add_file(struct pt_image *image, const char *filename,
304 		      uint64_t offset, uint64_t size,
305 		      const struct pt_asid *uasid, uint64_t vaddr)
306 {
307 	struct pt_section *section;
308 	struct pt_asid asid;
309 	int errcode;
310 
311 	if (!image || !filename)
312 		return -pte_invalid;
313 
314 	errcode = pt_asid_from_user(&asid, uasid);
315 	if (errcode < 0)
316 		return errcode;
317 
318 	section = pt_mk_section(filename, offset, size);
319 	if (!section)
320 		return -pte_invalid;
321 
322 	errcode = pt_image_add(image, section, &asid, vaddr, 0);
323 	if (errcode < 0) {
324 		(void) pt_section_put(section);
325 		return errcode;
326 	}
327 
328 	/* The image list got its own reference; let's drop ours. */
329 	errcode = pt_section_put(section);
330 	if (errcode < 0)
331 		return errcode;
332 
333 	return 0;
334 }
335 
336 int pt_image_copy(struct pt_image *image, const struct pt_image *src)
337 {
338 	struct pt_section_list *list;
339 	int ignored;
340 
341 	if (!image || !src)
342 		return -pte_invalid;
343 
344 	/* There is nothing to do if we copy an image to itself.
345 	 *
346 	 * Besides, pt_image_add() may move sections around, which would
347 	 * interfere with our section iteration.
348 	 */
349 	if (image == src)
350 		return 0;
351 
352 	ignored = 0;
353 	for (list = src->sections; list; list = list->next) {
354 		int errcode;
355 
356 		errcode = pt_image_add(image, list->section.section,
357 				       &list->section.asid,
358 				       list->section.vaddr,
359 				       list->isid);
360 		if (errcode < 0)
361 			ignored += 1;
362 	}
363 
364 	return ignored;
365 }
366 
367 int pt_image_remove_by_filename(struct pt_image *image, const char *filename,
368 				const struct pt_asid *uasid)
369 {
370 	struct pt_section_list **list;
371 	struct pt_asid asid;
372 	int errcode, removed;
373 
374 	if (!image || !filename)
375 		return -pte_invalid;
376 
377 	errcode = pt_asid_from_user(&asid, uasid);
378 	if (errcode < 0)
379 		return errcode;
380 
381 	removed = 0;
382 	for (list = &image->sections; *list;) {
383 		struct pt_mapped_section *msec;
384 		const struct pt_section *sec;
385 		const struct pt_asid *masid;
386 		struct pt_section_list *trash;
387 		const char *tname;
388 
389 		trash = *list;
390 		msec = &trash->section;
391 		masid = pt_msec_asid(msec);
392 
393 		errcode = pt_asid_match(masid, &asid);
394 		if (errcode < 0)
395 			return errcode;
396 
397 		if (!errcode) {
398 			list = &trash->next;
399 			continue;
400 		}
401 
402 		sec = pt_msec_section(msec);
403 		tname = pt_section_filename(sec);
404 
405 		if (tname && (strcmp(tname, filename) == 0)) {
406 			*list = trash->next;
407 			pt_section_list_free(trash);
408 
409 			removed += 1;
410 		} else
411 			list = &trash->next;
412 	}
413 
414 	return removed;
415 }
416 
417 int pt_image_remove_by_asid(struct pt_image *image,
418 			    const struct pt_asid *uasid)
419 {
420 	struct pt_section_list **list;
421 	struct pt_asid asid;
422 	int errcode, removed;
423 
424 	if (!image)
425 		return -pte_invalid;
426 
427 	errcode = pt_asid_from_user(&asid, uasid);
428 	if (errcode < 0)
429 		return errcode;
430 
431 	removed = 0;
432 	for (list = &image->sections; *list;) {
433 		struct pt_mapped_section *msec;
434 		const struct pt_asid *masid;
435 		struct pt_section_list *trash;
436 
437 		trash = *list;
438 		msec = &trash->section;
439 		masid = pt_msec_asid(msec);
440 
441 		errcode = pt_asid_match(masid, &asid);
442 		if (errcode < 0)
443 			return errcode;
444 
445 		if (!errcode) {
446 			list = &trash->next;
447 			continue;
448 		}
449 
450 		*list = trash->next;
451 		pt_section_list_free(trash);
452 
453 		removed += 1;
454 	}
455 
456 	return removed;
457 }
458 
459 int pt_image_set_callback(struct pt_image *image,
460 			  read_memory_callback_t *callback, void *context)
461 {
462 	if (!image)
463 		return -pte_invalid;
464 
465 	image->readmem.callback = callback;
466 	image->readmem.context = context;
467 
468 	return 0;
469 }
470 
471 static int pt_image_read_callback(struct pt_image *image, int *isid,
472 				  uint8_t *buffer, uint16_t size,
473 				  const struct pt_asid *asid, uint64_t addr)
474 {
475 	read_memory_callback_t *callback;
476 
477 	if (!image || !isid)
478 		return -pte_internal;
479 
480 	callback = image->readmem.callback;
481 	if (!callback)
482 		return -pte_nomap;
483 
484 	*isid = 0;
485 
486 	return callback(buffer, size, asid, addr, image->readmem.context);
487 }
488 
489 /* Check whether a mapped section contains an address.
490  *
491  * Returns zero if @msec contains @vaddr.
492  * Returns a negative error code otherwise.
493  * Returns -pte_nomap if @msec does not contain @vaddr.
494  */
495 static inline int pt_image_check_msec(const struct pt_mapped_section *msec,
496 				      const struct pt_asid *asid,
497 				      uint64_t vaddr)
498 {
499 	const struct pt_asid *masid;
500 	uint64_t begin, end;
501 	int errcode;
502 
503 	if (!msec)
504 		return -pte_internal;
505 
506 	begin = pt_msec_begin(msec);
507 	end = pt_msec_end(msec);
508 	if (vaddr < begin || end <= vaddr)
509 		return -pte_nomap;
510 
511 	masid = pt_msec_asid(msec);
512 	errcode = pt_asid_match(masid, asid);
513 	if (errcode <= 0) {
514 		if (!errcode)
515 			errcode = -pte_nomap;
516 
517 		return errcode;
518 	}
519 
520 	return 0;
521 }
522 
523 /* Find the section containing a given address in a given address space.
524  *
525  * On success, the found section is moved to the front of the section list.
526  * If caching is enabled, maps the section.
527  *
528  * Returns zero on success, a negative error code otherwise.
529  */
530 static int pt_image_fetch_section(struct pt_image *image,
531 				  const struct pt_asid *asid, uint64_t vaddr)
532 {
533 	struct pt_section_list **start, **list;
534 
535 	if (!image)
536 		return -pte_internal;
537 
538 	start = &image->sections;
539 	for (list = start; *list;) {
540 		struct pt_mapped_section *msec;
541 		struct pt_section_list *elem;
542 		int errcode;
543 
544 		elem = *list;
545 		msec = &elem->section;
546 
547 		errcode = pt_image_check_msec(msec, asid, vaddr);
548 		if (errcode < 0) {
549 			if (errcode != -pte_nomap)
550 				return errcode;
551 
552 			list = &elem->next;
553 			continue;
554 		}
555 
556 		/* Move the section to the front if it isn't already. */
557 		if (list != start) {
558 			*list = elem->next;
559 			elem->next = *start;
560 			*start = elem;
561 		}
562 
563 		return 0;
564 	}
565 
566 	return -pte_nomap;
567 }
568 
569 int pt_image_read(struct pt_image *image, int *isid, uint8_t *buffer,
570 		  uint16_t size, const struct pt_asid *asid, uint64_t addr)
571 {
572 	struct pt_mapped_section *msec;
573 	struct pt_section_list *slist;
574 	struct pt_section *section;
575 	int errcode, status;
576 
577 	if (!image || !isid)
578 		return -pte_internal;
579 
580 	errcode = pt_image_fetch_section(image, asid, addr);
581 	if (errcode < 0) {
582 		if (errcode != -pte_nomap)
583 			return errcode;
584 
585 		return pt_image_read_callback(image, isid, buffer, size, asid,
586 					      addr);
587 	}
588 
589 	slist = image->sections;
590 	if (!slist)
591 		return -pte_internal;
592 
593 	*isid = slist->isid;
594 	msec = &slist->section;
595 
596 	section = pt_msec_section(msec);
597 
598 	errcode = pt_section_map(section);
599 	if (errcode < 0)
600 		return errcode;
601 
602 	status = pt_msec_read(msec, buffer, size, addr);
603 
604 	errcode = pt_section_unmap(section);
605 		if (errcode < 0)
606 			return errcode;
607 
608 	if (status < 0) {
609 		if (status != -pte_nomap)
610 			return status;
611 
612 		return pt_image_read_callback(image, isid, buffer, size, asid,
613 					      addr);
614 	}
615 
616 	return status;
617 }
618 
619 int pt_image_add_cached(struct pt_image *image,
620 			struct pt_image_section_cache *iscache, int isid,
621 			const struct pt_asid *uasid)
622 {
623 	struct pt_section *section;
624 	struct pt_asid asid;
625 	uint64_t vaddr;
626 	int errcode, status;
627 
628 	if (!image || !iscache)
629 		return -pte_invalid;
630 
631 	errcode = pt_iscache_lookup(iscache, &section, &vaddr, isid);
632 	if (errcode < 0)
633 		return errcode;
634 
635 	errcode = pt_asid_from_user(&asid, uasid);
636 	if (errcode < 0)
637 		return errcode;
638 
639 	status = pt_image_add(image, section, &asid, vaddr, isid);
640 
641 	/* We grab a reference when we add the section.  Drop the one we
642 	 * obtained from cache lookup.
643 	 */
644 	errcode = pt_section_put(section);
645 	if (errcode < 0)
646 		return errcode;
647 
648 	return status;
649 }
650 
651 int pt_image_find(struct pt_image *image, struct pt_mapped_section *usec,
652 		  const struct pt_asid *asid, uint64_t vaddr)
653 {
654 	struct pt_mapped_section *msec;
655 	struct pt_section_list *slist;
656 	struct pt_section *section;
657 	int errcode;
658 
659 	if (!image || !usec)
660 		return -pte_internal;
661 
662 	errcode = pt_image_fetch_section(image, asid, vaddr);
663 	if (errcode < 0)
664 		return errcode;
665 
666 	slist = image->sections;
667 	if (!slist)
668 		return -pte_internal;
669 
670 	msec = &slist->section;
671 	section = pt_msec_section(msec);
672 
673 	errcode = pt_section_get(section);
674 	if (errcode < 0)
675 		return errcode;
676 
677 	*usec = *msec;
678 
679 	return slist->isid;
680 }
681 
682 int pt_image_validate(const struct pt_image *image,
683 		      const struct pt_mapped_section *usec, uint64_t vaddr,
684 		      int isid)
685 {
686 	const struct pt_section_list *slist;
687 	uint64_t begin, end;
688 	int status;
689 
690 	if (!image || !usec)
691 		return -pte_internal;
692 
693 	/* Check that @vaddr lies within @usec. */
694 	begin = pt_msec_begin(usec);
695 	end = pt_msec_end(usec);
696 	if (vaddr < begin || end <= vaddr)
697 		return -pte_nomap;
698 
699 	/* We assume that @usec is a copy of the top of our stack and accept
700 	 * sporadic validation fails if it isn't, e.g. because it has moved
701 	 * down.
702 	 *
703 	 * A failed validation requires decoders to re-fetch the section so it
704 	 * only results in a (relatively small) performance loss.
705 	 */
706 	slist = image->sections;
707 	if (!slist)
708 		return -pte_nomap;
709 
710 	if (slist->isid != isid)
711 		return -pte_nomap;
712 
713 	status = memcmp(&slist->section, usec, sizeof(*usec));
714 	if (status)
715 		return -pte_nomap;
716 
717 	return 0;
718 }
719