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