linux/tools/perf/arch/x86/util/machine.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/types.h>
   3#include <linux/string.h>
   4#include <stdlib.h>
   5
   6#include "../../util/util.h"
   7#include "../../util/machine.h"
   8#include "../../util/map.h"
   9#include "../../util/symbol.h"
  10#include <linux/ctype.h>
  11
  12#include <symbol/kallsyms.h>
  13
  14#if defined(__x86_64__)
  15
  16struct extra_kernel_map_info {
  17        int cnt;
  18        int max_cnt;
  19        struct extra_kernel_map *maps;
  20        bool get_entry_trampolines;
  21        u64 entry_trampoline;
  22};
  23
  24static int add_extra_kernel_map(struct extra_kernel_map_info *mi, u64 start,
  25                                u64 end, u64 pgoff, const char *name)
  26{
  27        if (mi->cnt >= mi->max_cnt) {
  28                void *buf;
  29                size_t sz;
  30
  31                mi->max_cnt = mi->max_cnt ? mi->max_cnt * 2 : 32;
  32                sz = sizeof(struct extra_kernel_map) * mi->max_cnt;
  33                buf = realloc(mi->maps, sz);
  34                if (!buf)
  35                        return -1;
  36                mi->maps = buf;
  37        }
  38
  39        mi->maps[mi->cnt].start = start;
  40        mi->maps[mi->cnt].end   = end;
  41        mi->maps[mi->cnt].pgoff = pgoff;
  42        strlcpy(mi->maps[mi->cnt].name, name, KMAP_NAME_LEN);
  43
  44        mi->cnt += 1;
  45
  46        return 0;
  47}
  48
  49static int find_extra_kernel_maps(void *arg, const char *name, char type,
  50                                  u64 start)
  51{
  52        struct extra_kernel_map_info *mi = arg;
  53
  54        if (!mi->entry_trampoline && kallsyms2elf_binding(type) == STB_GLOBAL &&
  55            !strcmp(name, "_entry_trampoline")) {
  56                mi->entry_trampoline = start;
  57                return 0;
  58        }
  59
  60        if (is_entry_trampoline(name)) {
  61                u64 end = start + page_size;
  62
  63                return add_extra_kernel_map(mi, start, end, 0, name);
  64        }
  65
  66        return 0;
  67}
  68
  69int machine__create_extra_kernel_maps(struct machine *machine,
  70                                      struct dso *kernel)
  71{
  72        struct extra_kernel_map_info mi = { .cnt = 0, };
  73        char filename[PATH_MAX];
  74        int ret;
  75        int i;
  76
  77        machine__get_kallsyms_filename(machine, filename, PATH_MAX);
  78
  79        if (symbol__restricted_filename(filename, "/proc/kallsyms"))
  80                return 0;
  81
  82        ret = kallsyms__parse(filename, &mi, find_extra_kernel_maps);
  83        if (ret)
  84                goto out_free;
  85
  86        if (!mi.entry_trampoline)
  87                goto out_free;
  88
  89        for (i = 0; i < mi.cnt; i++) {
  90                struct extra_kernel_map *xm = &mi.maps[i];
  91
  92                xm->pgoff = mi.entry_trampoline;
  93                ret = machine__create_extra_kernel_map(machine, kernel, xm);
  94                if (ret)
  95                        goto out_free;
  96        }
  97
  98        machine->trampolines_mapped = mi.cnt;
  99out_free:
 100        free(mi.maps);
 101        return ret;
 102}
 103
 104#endif
 105