20 #include <sys/utsname.h>
23 #define KSYM_NAME_LEN 256
26 static void dso_cache__free(
struct rb_root *root);
27 static int dso__load_kernel_sym(
struct dso *
dso,
struct map *
map,
29 static int dso__load_guest_kernel_sym(
struct dso *
dso,
struct map *
map,
31 static int vmlinux_path__nr_entries;
32 static char **vmlinux_path;
37 .try_vmlinux_path =
true,
57 #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
65 #define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data)
70 return strlen(
"[unknown]");
94 symbol_type =
toupper(symbol_type);
98 return symbol_type ==
'T' || symbol_type ==
'W';
100 return symbol_type ==
'D';
106 static int prefix_underscores_count(
const char *
str)
119 static int choose_best_symbol(
struct symbol *syma,
struct symbol *symb)
127 if ((b == 0) && (a > 0))
129 else if ((a == 0) && (b > 0))
149 a = prefix_underscores_count(syma->
name);
150 b = prefix_underscores_count(symb->
name);
182 if (choose_best_symbol(curr, next) ==
SYMBOL_A) {
238 static void map_groups__fixup_end(
struct map_groups *mg)
249 sizeof(*sym) + namelen));
254 sym = ((
void *)sym) + symbol_conf.
priv_size;
257 sym->
end = len ? start + len - 1 :
start;
262 __func__, name, start, sym->
end);
273 static size_t symbol__fprintf(
struct symbol *sym, FILE *
fp)
288 if (sym && sym->
name) {
292 length +=
fprintf(fp,
"+0x%lx", offset);
296 return fprintf(fp,
"[unknown]");
312 static void dso__set_short_name(
struct dso *
dso,
const char *
name)
320 static void dso__set_basename(
struct dso *dso)
322 dso__set_short_name(dso, basename(dso->
long_name));
327 struct dso *dso = calloc(1,
sizeof(*dso) +
strlen(name) + 1);
333 dso__set_short_name(dso, dso->
name);
344 INIT_LIST_HEAD(&dso->
node);
367 symbols__delete(&dso->
symbols[i]);
372 dso_cache__free(&dso->
cache);
397 rb_link_node(&sym->
rb_node, parent, p);
415 else if (ip > s->
end)
429 static void symbols__insert_by_name(
struct rb_root *symbols,
struct symbol *sym)
445 rb_link_node(&symn->
rb_node, parent, p);
449 static void symbols__sort_by_name(
struct rb_root *symbols,
456 symbols__insert_by_name(symbols, pos);
460 static struct symbol *symbols__find_by_name(
struct rb_root *symbols,
491 return symbols__find(&dso->
symbols[type], addr);
497 return symbols__find_by_name(&dso->
symbol_names[type], name);
502 dso__set_sorted_by_name(dso, type);
510 const u8 *
raw = build_id;
513 for (i = 0; i < len; ++
i) {
519 return raw - build_id;
527 return fprintf(fp,
"%s", sbuild_id);
553 dso->
loaded ?
"" :
"NOT ");
558 ret += symbol__fprintf(pos, fp);
565 int (*process_symbol)(
void *arg,
const char *name,
571 FILE *
file = fopen(filename,
"r");
578 while (!feof(file)) {
584 line_len = getline(&line, &n, file);
585 if (line_len < 0 || !line)
588 line[--line_len] =
'\0';
593 if (len + 2 >= line_len)
596 symbol_type = line[len];
598 symbol_name = line + len;
599 len = line_len - len;
606 err = process_symbol(arg, symbol_name,
625 static u8 kallsyms2elf_type(
char type)
633 static int map__process_kallsym_symbol(
void *arg,
const char *name,
648 sym =
symbol__new(start, 0, kallsyms2elf_type(type), name);
665 static int dso__load_all_kallsyms(
struct dso *dso,
const char *filename,
677 static int dso__split_kallsyms(
struct dso *dso,
struct map *
map,
680 struct map_groups *kmaps = map__kmap(map)->kmaps;
682 struct map *curr_map =
map;
684 int count = 0, moved = 0;
687 int kernel_range = 0;
702 if (
strcmp(curr_map->
dso->short_name, module)) {
703 if (curr_map != map &&
705 machine__is_default_guest(machine)) {
713 dso__set_loaded(curr_map->
dso,
719 if (curr_map ==
NULL) {
720 pr_debug(
"%s/proc/{kallsyms,modules} "
721 "inconsistency while looking "
722 "for \"%s\" module!\n",
728 if (curr_map->
dso->loaded &&
729 !machine__is_default_guest(machine))
738 }
else if (curr_map != map) {
748 snprintf(dso_name,
sizeof(dso_name),
752 snprintf(dso_name,
sizeof(dso_name),
763 if (curr_map ==
NULL) {
769 map_groups__insert(kmaps, curr_map);
773 if (filter &&
filter(curr_map, pos)) {
777 if (curr_map != map) {
786 if (curr_map != map &&
788 machine__is_default_guest(kmaps->
machine)) {
789 dso__set_loaded(curr_map->
dso, curr_map->
type);
792 return count + moved;
795 static bool symbol__restricted_filename(
const char *filename,
796 const char *restricted_filename)
798 bool restricted =
false;
801 char *
r = realpath(filename,
NULL);
804 restricted =
strcmp(r, restricted_filename) == 0;
816 if (symbol__restricted_filename(filename,
"/proc/kallsyms"))
819 if (dso__load_all_kallsyms(dso, filename, map) < 0)
830 return dso__split_kallsyms(dso, map, filter);
833 static int dso__load_perf_map(
struct dso *dso,
struct map *map,
845 while (!feof(file)) {
850 line_len = getline(&line, &n, file);
857 line[--line_len] =
'\0';
862 if (len + 2 >= line_len)
865 len +=
hex2u64(line + len, &size);
868 if (len + 2 >= line_len)
874 goto out_delete_line;
876 if (filter &&
filter(map, sym))
902 bool have_build_id =
false;
906 if (with_hits && !pos->
hit)
909 have_build_id =
true;
914 have_build_id =
true;
919 return have_build_id;
924 static const char origin[] = {
946 char *root_dir,
char *file,
size_t size)
957 while (debuglink != file && *debuglink !=
'/')
959 if (*debuglink ==
'/')
962 size - (debuglink - file));
967 if (symbol_conf.
symfs[0] ||
973 snprintf(file, size,
"%s/usr/lib/debug%s.debug",
978 snprintf(file, size,
"%s/usr/lib/debug%s",
992 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
993 symbol_conf.
symfs, build_id_hex, build_id_hex + 2);
1036 dso__set_loaded(dso, map->
type);
1039 return dso__load_kernel_sym(dso, map, filter);
1041 return dso__load_guest_kernel_sym(dso, map, filter);
1044 machine = map->
groups->machine;
1057 if (lstat(dso->
name, &st) < 0)
1061 pr_warning(
"File %s not owned by current user or root, "
1062 "ignoring it.\n", dso->
name);
1066 ret = dso__load_perf_map(dso, map, filter);
1081 bool next_slot =
false;
1106 if (syms_ss && runtime_ss)
1112 if (!runtime_ss && !syms_ss)
1115 if (runtime_ss && !syms_ss) {
1116 syms_ss = runtime_ss;
1120 if (!runtime_ss && syms_ss)
1121 runtime_ss = syms_ss;
1124 ret =
dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0);
1136 for (; ss_pos > 0; ss_pos--)
1146 enum map_type type,
const char *name)
1153 if (map->
dso &&
strcmp(map->
dso->short_name, name) == 0)
1160 static int dso__kernel_module_get_build_id(
struct dso *dso,
1161 const char *root_dir)
1170 snprintf(filename,
sizeof(filename),
1171 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1172 root_dir, (
int)
strlen(name) - 1, name);
1181 static int map_groups__set_modules_path_dir(
struct map_groups *mg,
1182 const char *dir_name)
1185 DIR *
dir = opendir(dir_name);
1189 pr_debug(
"%s: cannot open %s dir\n", __func__, dir_name);
1193 while ((dent = readdir(dir)) !=
NULL) {
1198 snprintf(path,
sizeof(path),
"%s/%s", dir_name, dent->d_name);
1203 if (!
strcmp(dent->d_name,
".") ||
1204 !
strcmp(dent->d_name,
".."))
1207 ret = map_groups__set_modules_path_dir(mg, path);
1211 char *dot =
strrchr(dent->d_name,
'.'),
1218 snprintf(dso_name,
sizeof(dso_name),
"[%.*s]",
1219 (
int)(dot - dent->d_name), dent->d_name);
1227 long_name = strdup(path);
1228 if (long_name ==
NULL) {
1233 map->
dso->lname_alloc = 1;
1234 dso__kernel_module_get_build_id(map->
dso,
"");
1243 static char *get_kernel_version(
const char *root_dir)
1248 const char *
prefix =
"Linux version ";
1250 sprintf(version,
"%s/proc/version", root_dir);
1251 file = fopen(version,
"r");
1256 tmp = fgets(version,
sizeof(version), file);
1259 name =
strstr(version, prefix);
1267 return strdup(name);
1270 static int machine__set_modules_path(
struct machine *machine)
1275 version = get_kernel_version(machine->
root_dir);
1279 snprintf(modules_path,
sizeof(modules_path),
"%s/lib/modules/%s/kernel",
1283 return map_groups__set_modules_path_dir(&machine->
kmaps, modules_path);
1287 const char *filename)
1299 if (machine__is_host(machine))
1303 map_groups__insert(&machine->
kmaps, map);
1307 static int machine__create_modules(
struct machine *machine)
1313 const char *modules;
1316 if (machine__is_default_guest(machine))
1323 if (symbol__restricted_filename(path,
"/proc/modules"))
1326 file = fopen(modules,
"r");
1330 while (!feof(file)) {
1336 line_len = getline(&line, &n, file);
1343 line[--line_len] =
'\0';
1357 snprintf(name,
sizeof(name),
"[%s]", line);
1360 goto out_delete_line;
1361 dso__kernel_module_get_build_id(map->
dso, machine->
root_dir);
1367 return machine__set_modules_path(machine);
1383 snprintf(symfs_vmlinux,
sizeof(symfs_vmlinux),
"%s%s",
1384 symbol_conf.
symfs, vmlinux);
1391 if (
symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
1399 dso__set_loaded(dso, map->
type);
1400 pr_debug(
"Using %s for symbols\n", symfs_vmlinux);
1412 pr_debug(
"Looking at the vmlinux_path (%d entries long)\n",
1413 vmlinux_path__nr_entries + 1);
1416 if (filename !=
NULL) {
1423 for (i = 0; i < vmlinux_path__nr_entries; ++
i) {
1434 static int dso__load_kernel_sym(
struct dso *dso,
struct map *map,
1438 const char *kallsyms_filename =
NULL;
1439 char *kallsyms_allocated_filename =
NULL;
1471 if (vmlinux_path !=
NULL) {
1478 if (symbol_conf.
symfs[0] != 0)
1491 sizeof(kallsyms_build_id)) == 0) {
1493 kallsyms_filename =
"/proc/kallsyms";
1504 if (asprintf(&kallsyms_allocated_filename,
1505 "%s/.debug/[kernel.kallsyms]/%s",
1506 getenv(
"HOME"), sbuild_id) == -1) {
1507 pr_err(
"Not enough memory for kallsyms file lookup\n");
1511 kallsyms_filename = kallsyms_allocated_filename;
1513 if (
access(kallsyms_filename, F_OK)) {
1514 pr_err(
"No kallsyms or vmlinux with build-id %s "
1515 "was found\n", sbuild_id);
1516 free(kallsyms_allocated_filename);
1524 kallsyms_filename =
"/proc/kallsyms";
1530 pr_debug(
"Using %s for symbols\n", kallsyms_filename);
1531 free(kallsyms_allocated_filename);
1543 static int dso__load_guest_kernel_sym(
struct dso *dso,
struct map *map,
1547 const char *kallsyms_filename =
NULL;
1552 pr_debug(
"Guest kernel map hasn't the point to groups\n");
1555 machine = map->
groups->machine;
1557 if (machine__is_default_guest(machine)) {
1570 if (!kallsyms_filename)
1574 kallsyms_filename =
path;
1579 pr_debug(
"Using %s for symbols\n", kallsyms_filename);
1583 if (kallsyms_filename !=
NULL) {
1617 dso__set_basename(dso);
1652 static size_t __dsos__fprintf_buildid(
struct list_head *
head, FILE *
fp,
1659 if (with_hits && !pos->
hit)
1670 return __dsos__fprintf_buildid(&machine->
kernel_dsos, fp, with_hits) +
1671 __dsos__fprintf_buildid(&machine->
user_dsos, fp, with_hits);
1675 FILE *fp,
bool with_hits)
1688 dso__kernel_findnew(
struct machine *machine,
const char *name,
1701 dso__set_short_name(dso, short_name);
1712 if (machine__is_default_guest(machine))
1720 static struct dso *machine__get_kernel(
struct machine *machine)
1722 const char *vmlinux_name =
NULL;
1725 if (machine__is_host(machine)) {
1728 vmlinux_name =
"[kernel.kallsyms]";
1730 kernel = dso__kernel_findnew(machine, vmlinux_name,
1736 if (machine__is_default_guest(machine))
1742 kernel = dso__kernel_findnew(machine, vmlinux_name,
1757 static int symbol__in_kernel(
void *arg,
const char *name,
1770 static u64 machine__get_kernel_start_addr(
struct machine *machine)
1776 if (machine__is_host(machine)) {
1777 filename =
"/proc/kallsyms";
1779 if (machine__is_default_guest(machine))
1787 if (symbol__restricted_filename(filename,
"/proc/kallsyms"))
1799 u64 start = machine__get_kernel_start_addr(machine);
1813 map_groups__insert(&machine->
kmaps,
1831 map_groups__remove(&machine->
kmaps,
1853 struct dso *kernel = machine__get_kernel(machine);
1855 if (kernel ==
NULL ||
1859 if (symbol_conf.
use_modules && machine__create_modules(machine) < 0) {
1860 if (machine__is_host(machine))
1861 pr_debug(
"Problems creating module maps, "
1862 "continuing anyway...\n");
1864 pr_debug(
"Problems creating module maps for guest %d, "
1865 "continuing anyway...\n", machine->
pid);
1871 map_groups__fixup_end(&machine->
kmaps);
1875 static void vmlinux_path__exit(
void)
1877 while (--vmlinux_path__nr_entries >= 0) {
1878 free(vmlinux_path[vmlinux_path__nr_entries]);
1879 vmlinux_path[vmlinux_path__nr_entries] =
NULL;
1883 vmlinux_path =
NULL;
1886 static int vmlinux_path__init(
void)
1891 vmlinux_path =
malloc(
sizeof(
char *) * 5);
1892 if (vmlinux_path ==
NULL)
1895 vmlinux_path[vmlinux_path__nr_entries] = strdup(
"vmlinux");
1896 if (vmlinux_path[vmlinux_path__nr_entries] ==
NULL)
1898 ++vmlinux_path__nr_entries;
1899 vmlinux_path[vmlinux_path__nr_entries] = strdup(
"/boot/vmlinux");
1900 if (vmlinux_path[vmlinux_path__nr_entries] ==
NULL)
1902 ++vmlinux_path__nr_entries;
1905 if (symbol_conf.
symfs[0] != 0)
1908 if (uname(&
uts) < 0)
1911 snprintf(bf,
sizeof(bf),
"/boot/vmlinux-%s",
uts.release);
1912 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1913 if (vmlinux_path[vmlinux_path__nr_entries] ==
NULL)
1915 ++vmlinux_path__nr_entries;
1916 snprintf(bf,
sizeof(bf),
"/lib/modules/%s/build/vmlinux",
uts.release);
1917 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1918 if (vmlinux_path[vmlinux_path__nr_entries] ==
NULL)
1920 ++vmlinux_path__nr_entries;
1921 snprintf(bf,
sizeof(bf),
"/usr/lib/debug/lib/modules/%s/vmlinux",
1923 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1924 if (vmlinux_path[vmlinux_path__nr_entries] ==
NULL)
1926 ++vmlinux_path__nr_entries;
1931 vmlinux_path__exit();
1944 printed +=
fprintf(fp,
"[0] %s\n", filename);
1947 for (i = 0; i < vmlinux_path__nr_entries; ++
i)
1948 printed +=
fprintf(fp,
"[%d] %s\n",
1954 static int setup_list(
struct strlist **
list,
const char *list_str,
1955 const char *list_name)
1957 if (list_str ==
NULL)
1962 pr_err(
"problems parsing %s list\n", list_name);
1968 static bool symbol__read_kptr_restrict(
void)
1972 if (geteuid() != 0) {
1973 FILE *fp = fopen(
"/proc/sys/kernel/kptr_restrict",
"r");
1977 if (fgets(line,
sizeof(line), fp) !=
NULL)
1978 value = atoi(line) != 0;
2000 sizeof(struct symbol));
2006 pr_err(
"'.' is the only non valid --field-separator argument\n");
2010 if (setup_list(&symbol_conf.
dso_list,
2016 goto out_free_dso_list;
2018 if (setup_list(&symbol_conf.
sym_list,
2020 goto out_free_comm_list;
2026 symfs = realpath(symbol_conf.
symfs,
NULL);
2028 symfs = symbol_conf.
symfs;
2029 if (
strcmp(symfs,
"/") == 0)
2030 symbol_conf.
symfs =
"";
2031 if (symfs != symbol_conf.
symfs)
2032 free((
void *)symfs);
2053 vmlinux_path__exit();
2062 if (machine ==
NULL)
2068 static int hex(
char ch)
2070 if ((ch >=
'0') && (ch <=
'9'))
2072 if ((ch >=
'a') && (ch <=
'f'))
2073 return ch -
'a' + 10;
2074 if ((ch >=
'A') && (ch <=
'F'))
2075 return ch -
'A' + 10;
2085 const char *p =
ptr;
2089 const int hex_val = hex(*p);
2094 *long_val = (*long_val << 4) | hex_val;
2130 for (i = 0; i < items; i++) {
2131 if (!
isdigit(namelist[i]->d_name[0])) {
2135 pid = (
pid_t)strtol(namelist[i]->d_name, &endp, 10);
2136 if ((*endp !=
'\0') ||
2137 (endp == namelist[
i]->d_name) ||
2139 pr_debug(
"invalid directory (%s). Skipping.\n",
2140 namelist[i]->d_name);
2143 sprintf(path,
"%s/%s/proc/kallsyms",
2145 namelist[i]->d_name);
2146 ret =
access(path, R_OK);
2148 pr_debug(
"Can't access file %s\n", path);
2180 dso__set_loaded(map->
dso, type);
2199 dso__set_loaded(map->
dso, type);
2208 struct map *map =
NULL;
2217 static int open_dso(
struct dso *dso,
struct machine *machine)
2219 char *root_dir = (
char *)
"";
2246 return open_dso(dso, machine);
2253 fd = open_dso(dso, machine);
2263 dso_cache__free(
struct rb_root *root)
2284 while (*p !=
NULL) {
2293 else if (offset >= end)
2307 u64 offset =
new->offset;
2309 while (*p !=
NULL) {
2318 else if (offset >= end)
2322 rb_link_node(&new->rb_node, parent, p);
2330 u64 cache_offset = offset - cache->
offset;
2331 u64 cache_size =
min(cache->
size - cache_offset, size);
2333 memcpy(data, cache->
data + cache_offset, cache_size);
2338 dso_cache__read(
struct dso *dso,
struct machine *machine,
2361 if (-1 == lseek(fd, cache_offset,
SEEK_SET))
2368 cache->
offset = cache_offset;
2370 dso_cache__insert(&dso->
cache, cache);
2372 ret = dso_cache__memcpy(cache, offset, data, size);
2383 static ssize_t dso_cache_read(
struct dso *dso,
struct machine *machine,
2388 cache = dso_cache__find(&dso->
cache, offset);
2390 return dso_cache__memcpy(cache, offset, data, size);
2392 return dso_cache__read(dso, machine, offset, data, size);
2404 ret = dso_cache_read(dso, machine, offset, p, size);
2425 struct machine *machine,
u64 addr,