]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/processor-trace/libipt/src/pt_image.c
Import Intel Processor Trace decoder library from
[FreeBSD/FreeBSD.git] / contrib / processor-trace / libipt / src / pt_image.c
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 }