.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | 2 | #include <asm/bug.h> |
---|
3 | 3 | #include <linux/kernel.h> |
---|
| 4 | +#include <linux/string.h> |
---|
| 5 | +#include <linux/zalloc.h> |
---|
4 | 6 | #include <sys/time.h> |
---|
5 | 7 | #include <sys/resource.h> |
---|
6 | 8 | #include <sys/types.h> |
---|
.. | .. |
---|
8 | 10 | #include <unistd.h> |
---|
9 | 11 | #include <errno.h> |
---|
10 | 12 | #include <fcntl.h> |
---|
| 13 | +#include <stdlib.h> |
---|
| 14 | +#include <bpf/libbpf.h> |
---|
| 15 | +#include "bpf-event.h" |
---|
11 | 16 | #include "compress.h" |
---|
| 17 | +#include "env.h" |
---|
| 18 | +#include "namespaces.h" |
---|
12 | 19 | #include "path.h" |
---|
| 20 | +#include "map.h" |
---|
13 | 21 | #include "symbol.h" |
---|
14 | 22 | #include "srcline.h" |
---|
15 | 23 | #include "dso.h" |
---|
| 24 | +#include "dsos.h" |
---|
16 | 25 | #include "machine.h" |
---|
17 | 26 | #include "auxtrace.h" |
---|
18 | | -#include "util.h" |
---|
| 27 | +#include "util.h" /* O_CLOEXEC for older systems */ |
---|
19 | 28 | #include "debug.h" |
---|
20 | 29 | #include "string2.h" |
---|
21 | 30 | #include "vdso.h" |
---|
.. | .. |
---|
163 | 172 | break; |
---|
164 | 173 | } |
---|
165 | 174 | |
---|
166 | | - build_id__sprintf(dso->build_id, |
---|
167 | | - sizeof(dso->build_id), |
---|
168 | | - build_id_hex); |
---|
| 175 | + build_id__sprintf(&dso->bid, build_id_hex); |
---|
169 | 176 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/"); |
---|
170 | 177 | snprintf(filename + len, size - len, "%.2s/%s.debug", |
---|
171 | 178 | build_id_hex, build_id_hex + 2); |
---|
.. | .. |
---|
197 | 204 | case DSO_BINARY_TYPE__KALLSYMS: |
---|
198 | 205 | case DSO_BINARY_TYPE__GUEST_KALLSYMS: |
---|
199 | 206 | case DSO_BINARY_TYPE__JAVA_JIT: |
---|
| 207 | + case DSO_BINARY_TYPE__BPF_PROG_INFO: |
---|
| 208 | + case DSO_BINARY_TYPE__BPF_IMAGE: |
---|
| 209 | + case DSO_BINARY_TYPE__OOL: |
---|
200 | 210 | case DSO_BINARY_TYPE__NOT_FOUND: |
---|
201 | 211 | ret = -1; |
---|
202 | 212 | break; |
---|
.. | .. |
---|
404 | 414 | return -ENOMEM; |
---|
405 | 415 | } |
---|
406 | 416 | |
---|
407 | | - strxfrchar(m->name, '-', '_'); |
---|
| 417 | + strreplace(m->name, '-', '_'); |
---|
408 | 418 | } |
---|
409 | 419 | |
---|
410 | 420 | return 0; |
---|
.. | .. |
---|
442 | 452 | |
---|
443 | 453 | static void dso__list_del(struct dso *dso) |
---|
444 | 454 | { |
---|
445 | | - list_del(&dso->data.open_entry); |
---|
| 455 | + list_del_init(&dso->data.open_entry); |
---|
446 | 456 | WARN_ONCE(dso__data_open_cnt <= 0, |
---|
447 | 457 | "DSO data fd counter out of bounds."); |
---|
448 | 458 | dso__data_open_cnt--; |
---|
.. | .. |
---|
718 | 728 | return false; |
---|
719 | 729 | } |
---|
720 | 730 | |
---|
| 731 | +static ssize_t bpf_read(struct dso *dso, u64 offset, char *data) |
---|
| 732 | +{ |
---|
| 733 | + struct bpf_prog_info_node *node; |
---|
| 734 | + ssize_t size = DSO__DATA_CACHE_SIZE; |
---|
| 735 | + u64 len; |
---|
| 736 | + u8 *buf; |
---|
| 737 | + |
---|
| 738 | + node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, dso->bpf_prog.id); |
---|
| 739 | + if (!node || !node->info_linear) { |
---|
| 740 | + dso->data.status = DSO_DATA_STATUS_ERROR; |
---|
| 741 | + return -1; |
---|
| 742 | + } |
---|
| 743 | + |
---|
| 744 | + len = node->info_linear->info.jited_prog_len; |
---|
| 745 | + buf = (u8 *)(uintptr_t)node->info_linear->info.jited_prog_insns; |
---|
| 746 | + |
---|
| 747 | + if (offset >= len) |
---|
| 748 | + return -1; |
---|
| 749 | + |
---|
| 750 | + size = (ssize_t)min(len - offset, (u64)size); |
---|
| 751 | + memcpy(data, buf + offset, size); |
---|
| 752 | + return size; |
---|
| 753 | +} |
---|
| 754 | + |
---|
| 755 | +static int bpf_size(struct dso *dso) |
---|
| 756 | +{ |
---|
| 757 | + struct bpf_prog_info_node *node; |
---|
| 758 | + |
---|
| 759 | + node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, dso->bpf_prog.id); |
---|
| 760 | + if (!node || !node->info_linear) { |
---|
| 761 | + dso->data.status = DSO_DATA_STATUS_ERROR; |
---|
| 762 | + return -1; |
---|
| 763 | + } |
---|
| 764 | + |
---|
| 765 | + dso->data.file_size = node->info_linear->info.jited_prog_len; |
---|
| 766 | + return 0; |
---|
| 767 | +} |
---|
| 768 | + |
---|
721 | 769 | static void |
---|
722 | 770 | dso_cache__free(struct dso *dso) |
---|
723 | 771 | { |
---|
.. | .. |
---|
736 | 784 | pthread_mutex_unlock(&dso->lock); |
---|
737 | 785 | } |
---|
738 | 786 | |
---|
739 | | -static struct dso_cache *dso_cache__find(struct dso *dso, u64 offset) |
---|
| 787 | +static struct dso_cache *__dso_cache__find(struct dso *dso, u64 offset) |
---|
740 | 788 | { |
---|
741 | 789 | const struct rb_root *root = &dso->data.cache; |
---|
742 | 790 | struct rb_node * const *p = &root->rb_node; |
---|
.. | .. |
---|
795 | 843 | return cache; |
---|
796 | 844 | } |
---|
797 | 845 | |
---|
798 | | -static ssize_t |
---|
799 | | -dso_cache__memcpy(struct dso_cache *cache, u64 offset, |
---|
800 | | - u8 *data, u64 size) |
---|
| 846 | +static ssize_t dso_cache__memcpy(struct dso_cache *cache, u64 offset, u8 *data, |
---|
| 847 | + u64 size, bool out) |
---|
801 | 848 | { |
---|
802 | 849 | u64 cache_offset = offset - cache->offset; |
---|
803 | 850 | u64 cache_size = min(cache->size - cache_offset, size); |
---|
804 | 851 | |
---|
805 | | - memcpy(data, cache->data + cache_offset, cache_size); |
---|
| 852 | + if (out) |
---|
| 853 | + memcpy(data, cache->data + cache_offset, cache_size); |
---|
| 854 | + else |
---|
| 855 | + memcpy(cache->data + cache_offset, data, cache_size); |
---|
806 | 856 | return cache_size; |
---|
807 | 857 | } |
---|
808 | 858 | |
---|
809 | | -static ssize_t |
---|
810 | | -dso_cache__read(struct dso *dso, struct machine *machine, |
---|
811 | | - u64 offset, u8 *data, ssize_t size) |
---|
| 859 | +static ssize_t file_read(struct dso *dso, struct machine *machine, |
---|
| 860 | + u64 offset, char *data) |
---|
812 | 861 | { |
---|
813 | | - struct dso_cache *cache; |
---|
814 | | - struct dso_cache *old; |
---|
815 | 862 | ssize_t ret; |
---|
816 | 863 | |
---|
817 | | - do { |
---|
818 | | - u64 cache_offset; |
---|
| 864 | + pthread_mutex_lock(&dso__data_open_lock); |
---|
819 | 865 | |
---|
820 | | - cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE); |
---|
821 | | - if (!cache) |
---|
822 | | - return -ENOMEM; |
---|
| 866 | + /* |
---|
| 867 | + * dso->data.fd might be closed if other thread opened another |
---|
| 868 | + * file (dso) due to open file limit (RLIMIT_NOFILE). |
---|
| 869 | + */ |
---|
| 870 | + try_to_open_dso(dso, machine); |
---|
823 | 871 | |
---|
824 | | - pthread_mutex_lock(&dso__data_open_lock); |
---|
825 | | - |
---|
826 | | - /* |
---|
827 | | - * dso->data.fd might be closed if other thread opened another |
---|
828 | | - * file (dso) due to open file limit (RLIMIT_NOFILE). |
---|
829 | | - */ |
---|
830 | | - try_to_open_dso(dso, machine); |
---|
831 | | - |
---|
832 | | - if (dso->data.fd < 0) { |
---|
833 | | - ret = -errno; |
---|
834 | | - dso->data.status = DSO_DATA_STATUS_ERROR; |
---|
835 | | - break; |
---|
836 | | - } |
---|
837 | | - |
---|
838 | | - cache_offset = offset & DSO__DATA_CACHE_MASK; |
---|
839 | | - |
---|
840 | | - ret = pread(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE, cache_offset); |
---|
841 | | - if (ret <= 0) |
---|
842 | | - break; |
---|
843 | | - |
---|
844 | | - cache->offset = cache_offset; |
---|
845 | | - cache->size = ret; |
---|
846 | | - } while (0); |
---|
847 | | - |
---|
848 | | - pthread_mutex_unlock(&dso__data_open_lock); |
---|
849 | | - |
---|
850 | | - if (ret > 0) { |
---|
851 | | - old = dso_cache__insert(dso, cache); |
---|
852 | | - if (old) { |
---|
853 | | - /* we lose the race */ |
---|
854 | | - free(cache); |
---|
855 | | - cache = old; |
---|
856 | | - } |
---|
857 | | - |
---|
858 | | - ret = dso_cache__memcpy(cache, offset, data, size); |
---|
| 872 | + if (dso->data.fd < 0) { |
---|
| 873 | + dso->data.status = DSO_DATA_STATUS_ERROR; |
---|
| 874 | + ret = -errno; |
---|
| 875 | + goto out; |
---|
859 | 876 | } |
---|
860 | 877 | |
---|
861 | | - if (ret <= 0) |
---|
862 | | - free(cache); |
---|
863 | | - |
---|
| 878 | + ret = pread(dso->data.fd, data, DSO__DATA_CACHE_SIZE, offset); |
---|
| 879 | +out: |
---|
| 880 | + pthread_mutex_unlock(&dso__data_open_lock); |
---|
864 | 881 | return ret; |
---|
865 | 882 | } |
---|
866 | 883 | |
---|
867 | | -static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, |
---|
868 | | - u64 offset, u8 *data, ssize_t size) |
---|
| 884 | +static struct dso_cache *dso_cache__populate(struct dso *dso, |
---|
| 885 | + struct machine *machine, |
---|
| 886 | + u64 offset, ssize_t *ret) |
---|
| 887 | +{ |
---|
| 888 | + u64 cache_offset = offset & DSO__DATA_CACHE_MASK; |
---|
| 889 | + struct dso_cache *cache; |
---|
| 890 | + struct dso_cache *old; |
---|
| 891 | + |
---|
| 892 | + cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE); |
---|
| 893 | + if (!cache) { |
---|
| 894 | + *ret = -ENOMEM; |
---|
| 895 | + return NULL; |
---|
| 896 | + } |
---|
| 897 | + |
---|
| 898 | + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) |
---|
| 899 | + *ret = bpf_read(dso, cache_offset, cache->data); |
---|
| 900 | + else if (dso->binary_type == DSO_BINARY_TYPE__OOL) |
---|
| 901 | + *ret = DSO__DATA_CACHE_SIZE; |
---|
| 902 | + else |
---|
| 903 | + *ret = file_read(dso, machine, cache_offset, cache->data); |
---|
| 904 | + |
---|
| 905 | + if (*ret <= 0) { |
---|
| 906 | + free(cache); |
---|
| 907 | + return NULL; |
---|
| 908 | + } |
---|
| 909 | + |
---|
| 910 | + cache->offset = cache_offset; |
---|
| 911 | + cache->size = *ret; |
---|
| 912 | + |
---|
| 913 | + old = dso_cache__insert(dso, cache); |
---|
| 914 | + if (old) { |
---|
| 915 | + /* we lose the race */ |
---|
| 916 | + free(cache); |
---|
| 917 | + cache = old; |
---|
| 918 | + } |
---|
| 919 | + |
---|
| 920 | + return cache; |
---|
| 921 | +} |
---|
| 922 | + |
---|
| 923 | +static struct dso_cache *dso_cache__find(struct dso *dso, |
---|
| 924 | + struct machine *machine, |
---|
| 925 | + u64 offset, |
---|
| 926 | + ssize_t *ret) |
---|
| 927 | +{ |
---|
| 928 | + struct dso_cache *cache = __dso_cache__find(dso, offset); |
---|
| 929 | + |
---|
| 930 | + return cache ? cache : dso_cache__populate(dso, machine, offset, ret); |
---|
| 931 | +} |
---|
| 932 | + |
---|
| 933 | +static ssize_t dso_cache_io(struct dso *dso, struct machine *machine, |
---|
| 934 | + u64 offset, u8 *data, ssize_t size, bool out) |
---|
869 | 935 | { |
---|
870 | 936 | struct dso_cache *cache; |
---|
| 937 | + ssize_t ret = 0; |
---|
871 | 938 | |
---|
872 | | - cache = dso_cache__find(dso, offset); |
---|
873 | | - if (cache) |
---|
874 | | - return dso_cache__memcpy(cache, offset, data, size); |
---|
875 | | - else |
---|
876 | | - return dso_cache__read(dso, machine, offset, data, size); |
---|
| 939 | + cache = dso_cache__find(dso, machine, offset, &ret); |
---|
| 940 | + if (!cache) |
---|
| 941 | + return ret; |
---|
| 942 | + |
---|
| 943 | + return dso_cache__memcpy(cache, offset, data, size, out); |
---|
877 | 944 | } |
---|
878 | 945 | |
---|
879 | 946 | /* |
---|
880 | 947 | * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks |
---|
881 | 948 | * in the rb_tree. Any read to already cached data is served |
---|
882 | | - * by cached data. |
---|
| 949 | + * by cached data. Writes update the cache only, not the backing file. |
---|
883 | 950 | */ |
---|
884 | | -static ssize_t cached_read(struct dso *dso, struct machine *machine, |
---|
885 | | - u64 offset, u8 *data, ssize_t size) |
---|
| 951 | +static ssize_t cached_io(struct dso *dso, struct machine *machine, |
---|
| 952 | + u64 offset, u8 *data, ssize_t size, bool out) |
---|
886 | 953 | { |
---|
887 | 954 | ssize_t r = 0; |
---|
888 | 955 | u8 *p = data; |
---|
.. | .. |
---|
890 | 957 | do { |
---|
891 | 958 | ssize_t ret; |
---|
892 | 959 | |
---|
893 | | - ret = dso_cache_read(dso, machine, offset, p, size); |
---|
| 960 | + ret = dso_cache_io(dso, machine, offset, p, size, out); |
---|
894 | 961 | if (ret < 0) |
---|
895 | 962 | return ret; |
---|
896 | 963 | |
---|
.. | .. |
---|
910 | 977 | return r; |
---|
911 | 978 | } |
---|
912 | 979 | |
---|
913 | | -static int data_file_size(struct dso *dso, struct machine *machine) |
---|
| 980 | +static int file_size(struct dso *dso, struct machine *machine) |
---|
914 | 981 | { |
---|
915 | 982 | int ret = 0; |
---|
916 | 983 | struct stat st; |
---|
917 | 984 | char sbuf[STRERR_BUFSIZE]; |
---|
918 | | - |
---|
919 | | - if (dso->data.file_size) |
---|
920 | | - return 0; |
---|
921 | | - |
---|
922 | | - if (dso->data.status == DSO_DATA_STATUS_ERROR) |
---|
923 | | - return -1; |
---|
924 | 985 | |
---|
925 | 986 | pthread_mutex_lock(&dso__data_open_lock); |
---|
926 | 987 | |
---|
.. | .. |
---|
950 | 1011 | return ret; |
---|
951 | 1012 | } |
---|
952 | 1013 | |
---|
| 1014 | +int dso__data_file_size(struct dso *dso, struct machine *machine) |
---|
| 1015 | +{ |
---|
| 1016 | + if (dso->data.file_size) |
---|
| 1017 | + return 0; |
---|
| 1018 | + |
---|
| 1019 | + if (dso->data.status == DSO_DATA_STATUS_ERROR) |
---|
| 1020 | + return -1; |
---|
| 1021 | + |
---|
| 1022 | + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) |
---|
| 1023 | + return bpf_size(dso); |
---|
| 1024 | + |
---|
| 1025 | + return file_size(dso, machine); |
---|
| 1026 | +} |
---|
| 1027 | + |
---|
953 | 1028 | /** |
---|
954 | 1029 | * dso__data_size - Return dso data size |
---|
955 | 1030 | * @dso: dso object |
---|
.. | .. |
---|
959 | 1034 | */ |
---|
960 | 1035 | off_t dso__data_size(struct dso *dso, struct machine *machine) |
---|
961 | 1036 | { |
---|
962 | | - if (data_file_size(dso, machine)) |
---|
| 1037 | + if (dso__data_file_size(dso, machine)) |
---|
963 | 1038 | return -1; |
---|
964 | 1039 | |
---|
965 | 1040 | /* For now just estimate dso data size is close to file size */ |
---|
966 | 1041 | return dso->data.file_size; |
---|
967 | 1042 | } |
---|
968 | 1043 | |
---|
969 | | -static ssize_t data_read_offset(struct dso *dso, struct machine *machine, |
---|
970 | | - u64 offset, u8 *data, ssize_t size) |
---|
| 1044 | +static ssize_t data_read_write_offset(struct dso *dso, struct machine *machine, |
---|
| 1045 | + u64 offset, u8 *data, ssize_t size, |
---|
| 1046 | + bool out) |
---|
971 | 1047 | { |
---|
972 | | - if (data_file_size(dso, machine)) |
---|
| 1048 | + if (dso__data_file_size(dso, machine)) |
---|
973 | 1049 | return -1; |
---|
974 | 1050 | |
---|
975 | 1051 | /* Check the offset sanity. */ |
---|
.. | .. |
---|
979 | 1055 | if (offset + size < offset) |
---|
980 | 1056 | return -1; |
---|
981 | 1057 | |
---|
982 | | - return cached_read(dso, machine, offset, data, size); |
---|
| 1058 | + return cached_io(dso, machine, offset, data, size, out); |
---|
983 | 1059 | } |
---|
984 | 1060 | |
---|
985 | 1061 | /** |
---|
.. | .. |
---|
999 | 1075 | if (dso->data.status == DSO_DATA_STATUS_ERROR) |
---|
1000 | 1076 | return -1; |
---|
1001 | 1077 | |
---|
1002 | | - return data_read_offset(dso, machine, offset, data, size); |
---|
| 1078 | + return data_read_write_offset(dso, machine, offset, data, size, true); |
---|
1003 | 1079 | } |
---|
1004 | 1080 | |
---|
1005 | 1081 | /** |
---|
.. | .. |
---|
1018 | 1094 | { |
---|
1019 | 1095 | u64 offset = map->map_ip(map, addr); |
---|
1020 | 1096 | return dso__data_read_offset(dso, machine, offset, data, size); |
---|
| 1097 | +} |
---|
| 1098 | + |
---|
| 1099 | +/** |
---|
| 1100 | + * dso__data_write_cache_offs - Write data to dso data cache at file offset |
---|
| 1101 | + * @dso: dso object |
---|
| 1102 | + * @machine: machine object |
---|
| 1103 | + * @offset: file offset |
---|
| 1104 | + * @data: buffer to write |
---|
| 1105 | + * @size: size of the @data buffer |
---|
| 1106 | + * |
---|
| 1107 | + * Write into the dso file data cache, but do not change the file itself. |
---|
| 1108 | + */ |
---|
| 1109 | +ssize_t dso__data_write_cache_offs(struct dso *dso, struct machine *machine, |
---|
| 1110 | + u64 offset, const u8 *data_in, ssize_t size) |
---|
| 1111 | +{ |
---|
| 1112 | + u8 *data = (u8 *)data_in; /* cast away const to use same fns for r/w */ |
---|
| 1113 | + |
---|
| 1114 | + if (dso->data.status == DSO_DATA_STATUS_ERROR) |
---|
| 1115 | + return -1; |
---|
| 1116 | + |
---|
| 1117 | + return data_read_write_offset(dso, machine, offset, data, size, false); |
---|
| 1118 | +} |
---|
| 1119 | + |
---|
| 1120 | +/** |
---|
| 1121 | + * dso__data_write_cache_addr - Write data to dso data cache at dso address |
---|
| 1122 | + * @dso: dso object |
---|
| 1123 | + * @machine: machine object |
---|
| 1124 | + * @add: virtual memory address |
---|
| 1125 | + * @data: buffer to write |
---|
| 1126 | + * @size: size of the @data buffer |
---|
| 1127 | + * |
---|
| 1128 | + * External interface to write into the dso file data cache, but do not change |
---|
| 1129 | + * the file itself. |
---|
| 1130 | + */ |
---|
| 1131 | +ssize_t dso__data_write_cache_addr(struct dso *dso, struct map *map, |
---|
| 1132 | + struct machine *machine, u64 addr, |
---|
| 1133 | + const u8 *data, ssize_t size) |
---|
| 1134 | +{ |
---|
| 1135 | + u64 offset = map->map_ip(map, addr); |
---|
| 1136 | + return dso__data_write_cache_offs(dso, machine, offset, data, size); |
---|
1021 | 1137 | } |
---|
1022 | 1138 | |
---|
1023 | 1139 | struct map *dso__new_map(const char *name) |
---|
.. | .. |
---|
1053 | 1169 | return dso; |
---|
1054 | 1170 | } |
---|
1055 | 1171 | |
---|
1056 | | -/* |
---|
1057 | | - * Find a matching entry and/or link current entry to RB tree. |
---|
1058 | | - * Either one of the dso or name parameter must be non-NULL or the |
---|
1059 | | - * function will not work. |
---|
1060 | | - */ |
---|
1061 | | -static struct dso *__dso__findlink_by_longname(struct rb_root *root, |
---|
1062 | | - struct dso *dso, const char *name) |
---|
1063 | | -{ |
---|
1064 | | - struct rb_node **p = &root->rb_node; |
---|
1065 | | - struct rb_node *parent = NULL; |
---|
1066 | | - |
---|
1067 | | - if (!name) |
---|
1068 | | - name = dso->long_name; |
---|
1069 | | - /* |
---|
1070 | | - * Find node with the matching name |
---|
1071 | | - */ |
---|
1072 | | - while (*p) { |
---|
1073 | | - struct dso *this = rb_entry(*p, struct dso, rb_node); |
---|
1074 | | - int rc = strcmp(name, this->long_name); |
---|
1075 | | - |
---|
1076 | | - parent = *p; |
---|
1077 | | - if (rc == 0) { |
---|
1078 | | - /* |
---|
1079 | | - * In case the new DSO is a duplicate of an existing |
---|
1080 | | - * one, print a one-time warning & put the new entry |
---|
1081 | | - * at the end of the list of duplicates. |
---|
1082 | | - */ |
---|
1083 | | - if (!dso || (dso == this)) |
---|
1084 | | - return this; /* Find matching dso */ |
---|
1085 | | - /* |
---|
1086 | | - * The core kernel DSOs may have duplicated long name. |
---|
1087 | | - * In this case, the short name should be different. |
---|
1088 | | - * Comparing the short names to differentiate the DSOs. |
---|
1089 | | - */ |
---|
1090 | | - rc = strcmp(dso->short_name, this->short_name); |
---|
1091 | | - if (rc == 0) { |
---|
1092 | | - pr_err("Duplicated dso name: %s\n", name); |
---|
1093 | | - return NULL; |
---|
1094 | | - } |
---|
1095 | | - } |
---|
1096 | | - if (rc < 0) |
---|
1097 | | - p = &parent->rb_left; |
---|
1098 | | - else |
---|
1099 | | - p = &parent->rb_right; |
---|
1100 | | - } |
---|
1101 | | - if (dso) { |
---|
1102 | | - /* Add new node and rebalance tree */ |
---|
1103 | | - rb_link_node(&dso->rb_node, parent, p); |
---|
1104 | | - rb_insert_color(&dso->rb_node, root); |
---|
1105 | | - dso->root = root; |
---|
1106 | | - } |
---|
1107 | | - return NULL; |
---|
1108 | | -} |
---|
1109 | | - |
---|
1110 | | -static inline struct dso *__dso__find_by_longname(struct rb_root *root, |
---|
1111 | | - const char *name) |
---|
1112 | | -{ |
---|
1113 | | - return __dso__findlink_by_longname(root, NULL, name); |
---|
1114 | | -} |
---|
1115 | | - |
---|
1116 | | -void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) |
---|
| 1172 | +static void dso__set_long_name_id(struct dso *dso, const char *name, struct dso_id *id, bool name_allocated) |
---|
1117 | 1173 | { |
---|
1118 | 1174 | struct rb_root *root = dso->root; |
---|
1119 | 1175 | |
---|
.. | .. |
---|
1126 | 1182 | if (root) { |
---|
1127 | 1183 | rb_erase(&dso->rb_node, root); |
---|
1128 | 1184 | /* |
---|
1129 | | - * __dso__findlink_by_longname() isn't guaranteed to add it |
---|
1130 | | - * back, so a clean removal is required here. |
---|
| 1185 | + * __dsos__findnew_link_by_longname_id() isn't guaranteed to |
---|
| 1186 | + * add it back, so a clean removal is required here. |
---|
1131 | 1187 | */ |
---|
1132 | 1188 | RB_CLEAR_NODE(&dso->rb_node); |
---|
1133 | 1189 | dso->root = NULL; |
---|
.. | .. |
---|
1138 | 1194 | dso->long_name_allocated = name_allocated; |
---|
1139 | 1195 | |
---|
1140 | 1196 | if (root) |
---|
1141 | | - __dso__findlink_by_longname(root, dso, NULL); |
---|
| 1197 | + __dsos__findnew_link_by_longname_id(root, dso, NULL, id); |
---|
| 1198 | +} |
---|
| 1199 | + |
---|
| 1200 | +void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) |
---|
| 1201 | +{ |
---|
| 1202 | + dso__set_long_name_id(dso, name, NULL, name_allocated); |
---|
1142 | 1203 | } |
---|
1143 | 1204 | |
---|
1144 | 1205 | void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) |
---|
.. | .. |
---|
1152 | 1213 | dso->short_name = name; |
---|
1153 | 1214 | dso->short_name_len = strlen(name); |
---|
1154 | 1215 | dso->short_name_allocated = name_allocated; |
---|
1155 | | -} |
---|
1156 | | - |
---|
1157 | | -static void dso__set_basename(struct dso *dso) |
---|
1158 | | -{ |
---|
1159 | | - /* |
---|
1160 | | - * basename() may modify path buffer, so we must pass |
---|
1161 | | - * a copy. |
---|
1162 | | - */ |
---|
1163 | | - char *base, *lname = strdup(dso->long_name); |
---|
1164 | | - |
---|
1165 | | - if (!lname) |
---|
1166 | | - return; |
---|
1167 | | - |
---|
1168 | | - /* |
---|
1169 | | - * basename() may return a pointer to internal |
---|
1170 | | - * storage which is reused in subsequent calls |
---|
1171 | | - * so copy the result. |
---|
1172 | | - */ |
---|
1173 | | - base = strdup(basename(lname)); |
---|
1174 | | - |
---|
1175 | | - free(lname); |
---|
1176 | | - |
---|
1177 | | - if (!base) |
---|
1178 | | - return; |
---|
1179 | | - |
---|
1180 | | - dso__set_short_name(dso, base, true); |
---|
1181 | 1216 | } |
---|
1182 | 1217 | |
---|
1183 | 1218 | int dso__name_len(const struct dso *dso) |
---|
.. | .. |
---|
1205 | 1240 | dso->sorted_by_name = true; |
---|
1206 | 1241 | } |
---|
1207 | 1242 | |
---|
1208 | | -struct dso *dso__new(const char *name) |
---|
| 1243 | +struct dso *dso__new_id(const char *name, struct dso_id *id) |
---|
1209 | 1244 | { |
---|
1210 | 1245 | struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); |
---|
1211 | 1246 | |
---|
1212 | 1247 | if (dso != NULL) { |
---|
1213 | 1248 | strcpy(dso->name, name); |
---|
1214 | | - dso__set_long_name(dso, dso->name, false); |
---|
| 1249 | + if (id) |
---|
| 1250 | + dso->id = *id; |
---|
| 1251 | + dso__set_long_name_id(dso, dso->name, id, false); |
---|
1215 | 1252 | dso__set_short_name(dso, dso->name, false); |
---|
1216 | | - dso->symbols = dso->symbol_names = RB_ROOT; |
---|
| 1253 | + dso->symbols = dso->symbol_names = RB_ROOT_CACHED; |
---|
1217 | 1254 | dso->data.cache = RB_ROOT; |
---|
1218 | | - dso->inlined_nodes = RB_ROOT; |
---|
1219 | | - dso->srclines = RB_ROOT; |
---|
| 1255 | + dso->inlined_nodes = RB_ROOT_CACHED; |
---|
| 1256 | + dso->srclines = RB_ROOT_CACHED; |
---|
1220 | 1257 | dso->data.fd = -1; |
---|
1221 | 1258 | dso->data.status = DSO_DATA_STATUS_UNKNOWN; |
---|
1222 | 1259 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; |
---|
.. | .. |
---|
1228 | 1265 | dso->has_build_id = 0; |
---|
1229 | 1266 | dso->has_srcline = 1; |
---|
1230 | 1267 | dso->a2l_fails = 1; |
---|
1231 | | - dso->kernel = DSO_TYPE_USER; |
---|
| 1268 | + dso->kernel = DSO_SPACE__USER; |
---|
1232 | 1269 | dso->needs_swap = DSO_SWAP__UNSET; |
---|
1233 | 1270 | dso->comp = COMP_ID__NONE; |
---|
1234 | 1271 | RB_CLEAR_NODE(&dso->rb_node); |
---|
.. | .. |
---|
1240 | 1277 | } |
---|
1241 | 1278 | |
---|
1242 | 1279 | return dso; |
---|
| 1280 | +} |
---|
| 1281 | + |
---|
| 1282 | +struct dso *dso__new(const char *name) |
---|
| 1283 | +{ |
---|
| 1284 | + return dso__new_id(name, NULL); |
---|
1243 | 1285 | } |
---|
1244 | 1286 | |
---|
1245 | 1287 | void dso__delete(struct dso *dso) |
---|
.. | .. |
---|
1286 | 1328 | dso__delete(dso); |
---|
1287 | 1329 | } |
---|
1288 | 1330 | |
---|
1289 | | -void dso__set_build_id(struct dso *dso, void *build_id) |
---|
| 1331 | +void dso__set_build_id(struct dso *dso, struct build_id *bid) |
---|
1290 | 1332 | { |
---|
1291 | | - memcpy(dso->build_id, build_id, sizeof(dso->build_id)); |
---|
| 1333 | + dso->bid = *bid; |
---|
1292 | 1334 | dso->has_build_id = 1; |
---|
1293 | 1335 | } |
---|
1294 | 1336 | |
---|
1295 | | -bool dso__build_id_equal(const struct dso *dso, u8 *build_id) |
---|
| 1337 | +bool dso__build_id_equal(const struct dso *dso, struct build_id *bid) |
---|
1296 | 1338 | { |
---|
1297 | | - return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; |
---|
| 1339 | + if (dso->bid.size > bid->size && dso->bid.size == BUILD_ID_SIZE) { |
---|
| 1340 | + /* |
---|
| 1341 | + * For the backward compatibility, it allows a build-id has |
---|
| 1342 | + * trailing zeros. |
---|
| 1343 | + */ |
---|
| 1344 | + return !memcmp(dso->bid.data, bid->data, bid->size) && |
---|
| 1345 | + !memchr_inv(&dso->bid.data[bid->size], 0, |
---|
| 1346 | + dso->bid.size - bid->size); |
---|
| 1347 | + } |
---|
| 1348 | + |
---|
| 1349 | + return dso->bid.size == bid->size && |
---|
| 1350 | + memcmp(dso->bid.data, bid->data, dso->bid.size) == 0; |
---|
1298 | 1351 | } |
---|
1299 | 1352 | |
---|
1300 | 1353 | void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) |
---|
.. | .. |
---|
1304 | 1357 | if (machine__is_default_guest(machine)) |
---|
1305 | 1358 | return; |
---|
1306 | 1359 | sprintf(path, "%s/sys/kernel/notes", machine->root_dir); |
---|
1307 | | - if (sysfs__read_build_id(path, dso->build_id, |
---|
1308 | | - sizeof(dso->build_id)) == 0) |
---|
| 1360 | + if (sysfs__read_build_id(path, &dso->bid) == 0) |
---|
1309 | 1361 | dso->has_build_id = true; |
---|
1310 | 1362 | } |
---|
1311 | 1363 | |
---|
.. | .. |
---|
1323 | 1375 | "%s/sys/module/%.*s/notes/.note.gnu.build-id", |
---|
1324 | 1376 | root_dir, (int)strlen(name) - 1, name); |
---|
1325 | 1377 | |
---|
1326 | | - if (sysfs__read_build_id(filename, dso->build_id, |
---|
1327 | | - sizeof(dso->build_id)) == 0) |
---|
| 1378 | + if (sysfs__read_build_id(filename, &dso->bid) == 0) |
---|
1328 | 1379 | dso->has_build_id = true; |
---|
1329 | 1380 | |
---|
1330 | 1381 | return 0; |
---|
1331 | 1382 | } |
---|
1332 | 1383 | |
---|
1333 | | -bool __dsos__read_build_ids(struct list_head *head, bool with_hits) |
---|
1334 | | -{ |
---|
1335 | | - bool have_build_id = false; |
---|
1336 | | - struct dso *pos; |
---|
1337 | | - struct nscookie nsc; |
---|
1338 | | - |
---|
1339 | | - list_for_each_entry(pos, head, node) { |
---|
1340 | | - if (with_hits && !pos->hit && !dso__is_vdso(pos)) |
---|
1341 | | - continue; |
---|
1342 | | - if (pos->has_build_id) { |
---|
1343 | | - have_build_id = true; |
---|
1344 | | - continue; |
---|
1345 | | - } |
---|
1346 | | - nsinfo__mountns_enter(pos->nsinfo, &nsc); |
---|
1347 | | - if (filename__read_build_id(pos->long_name, pos->build_id, |
---|
1348 | | - sizeof(pos->build_id)) > 0) { |
---|
1349 | | - have_build_id = true; |
---|
1350 | | - pos->has_build_id = true; |
---|
1351 | | - } |
---|
1352 | | - nsinfo__mountns_exit(&nsc); |
---|
1353 | | - } |
---|
1354 | | - |
---|
1355 | | - return have_build_id; |
---|
1356 | | -} |
---|
1357 | | - |
---|
1358 | | -void __dsos__add(struct dsos *dsos, struct dso *dso) |
---|
1359 | | -{ |
---|
1360 | | - list_add_tail(&dso->node, &dsos->head); |
---|
1361 | | - __dso__findlink_by_longname(&dsos->root, dso, NULL); |
---|
1362 | | - /* |
---|
1363 | | - * It is now in the linked list, grab a reference, then garbage collect |
---|
1364 | | - * this when needing memory, by looking at LRU dso instances in the |
---|
1365 | | - * list with atomic_read(&dso->refcnt) == 1, i.e. no references |
---|
1366 | | - * anywhere besides the one for the list, do, under a lock for the |
---|
1367 | | - * list: remove it from the list, then a dso__put(), that probably will |
---|
1368 | | - * be the last and will then call dso__delete(), end of life. |
---|
1369 | | - * |
---|
1370 | | - * That, or at the end of the 'struct machine' lifetime, when all |
---|
1371 | | - * 'struct dso' instances will be removed from the list, in |
---|
1372 | | - * dsos__exit(), if they have no other reference from some other data |
---|
1373 | | - * structure. |
---|
1374 | | - * |
---|
1375 | | - * E.g.: after processing a 'perf.data' file and storing references |
---|
1376 | | - * to objects instantiated while processing events, we will have |
---|
1377 | | - * references to the 'thread', 'map', 'dso' structs all from 'struct |
---|
1378 | | - * hist_entry' instances, but we may not need anything not referenced, |
---|
1379 | | - * so we might as well call machines__exit()/machines__delete() and |
---|
1380 | | - * garbage collect it. |
---|
1381 | | - */ |
---|
1382 | | - dso__get(dso); |
---|
1383 | | -} |
---|
1384 | | - |
---|
1385 | | -void dsos__add(struct dsos *dsos, struct dso *dso) |
---|
1386 | | -{ |
---|
1387 | | - down_write(&dsos->lock); |
---|
1388 | | - __dsos__add(dsos, dso); |
---|
1389 | | - up_write(&dsos->lock); |
---|
1390 | | -} |
---|
1391 | | - |
---|
1392 | | -struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short) |
---|
1393 | | -{ |
---|
1394 | | - struct dso *pos; |
---|
1395 | | - |
---|
1396 | | - if (cmp_short) { |
---|
1397 | | - list_for_each_entry(pos, &dsos->head, node) |
---|
1398 | | - if (strcmp(pos->short_name, name) == 0) |
---|
1399 | | - return pos; |
---|
1400 | | - return NULL; |
---|
1401 | | - } |
---|
1402 | | - return __dso__find_by_longname(&dsos->root, name); |
---|
1403 | | -} |
---|
1404 | | - |
---|
1405 | | -struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) |
---|
1406 | | -{ |
---|
1407 | | - struct dso *dso; |
---|
1408 | | - down_read(&dsos->lock); |
---|
1409 | | - dso = __dsos__find(dsos, name, cmp_short); |
---|
1410 | | - up_read(&dsos->lock); |
---|
1411 | | - return dso; |
---|
1412 | | -} |
---|
1413 | | - |
---|
1414 | | -struct dso *__dsos__addnew(struct dsos *dsos, const char *name) |
---|
1415 | | -{ |
---|
1416 | | - struct dso *dso = dso__new(name); |
---|
1417 | | - |
---|
1418 | | - if (dso != NULL) { |
---|
1419 | | - __dsos__add(dsos, dso); |
---|
1420 | | - dso__set_basename(dso); |
---|
1421 | | - /* Put dso here because __dsos_add already got it */ |
---|
1422 | | - dso__put(dso); |
---|
1423 | | - } |
---|
1424 | | - return dso; |
---|
1425 | | -} |
---|
1426 | | - |
---|
1427 | | -struct dso *__dsos__findnew(struct dsos *dsos, const char *name) |
---|
1428 | | -{ |
---|
1429 | | - struct dso *dso = __dsos__find(dsos, name, false); |
---|
1430 | | - |
---|
1431 | | - return dso ? dso : __dsos__addnew(dsos, name); |
---|
1432 | | -} |
---|
1433 | | - |
---|
1434 | | -struct dso *dsos__findnew(struct dsos *dsos, const char *name) |
---|
1435 | | -{ |
---|
1436 | | - struct dso *dso; |
---|
1437 | | - down_write(&dsos->lock); |
---|
1438 | | - dso = dso__get(__dsos__findnew(dsos, name)); |
---|
1439 | | - up_write(&dsos->lock); |
---|
1440 | | - return dso; |
---|
1441 | | -} |
---|
1442 | | - |
---|
1443 | | -size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, |
---|
1444 | | - bool (skip)(struct dso *dso, int parm), int parm) |
---|
1445 | | -{ |
---|
1446 | | - struct dso *pos; |
---|
1447 | | - size_t ret = 0; |
---|
1448 | | - |
---|
1449 | | - list_for_each_entry(pos, head, node) { |
---|
1450 | | - if (skip && skip(pos, parm)) |
---|
1451 | | - continue; |
---|
1452 | | - ret += dso__fprintf_buildid(pos, fp); |
---|
1453 | | - ret += fprintf(fp, " %s\n", pos->long_name); |
---|
1454 | | - } |
---|
1455 | | - return ret; |
---|
1456 | | -} |
---|
1457 | | - |
---|
1458 | | -size_t __dsos__fprintf(struct list_head *head, FILE *fp) |
---|
1459 | | -{ |
---|
1460 | | - struct dso *pos; |
---|
1461 | | - size_t ret = 0; |
---|
1462 | | - |
---|
1463 | | - list_for_each_entry(pos, head, node) { |
---|
1464 | | - ret += dso__fprintf(pos, fp); |
---|
1465 | | - } |
---|
1466 | | - |
---|
1467 | | - return ret; |
---|
1468 | | -} |
---|
1469 | | - |
---|
1470 | | -size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) |
---|
| 1384 | +static size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) |
---|
1471 | 1385 | { |
---|
1472 | 1386 | char sbuild_id[SBUILD_ID_SIZE]; |
---|
1473 | 1387 | |
---|
1474 | | - build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); |
---|
| 1388 | + build_id__sprintf(&dso->bid, sbuild_id); |
---|
1475 | 1389 | return fprintf(fp, "%s", sbuild_id); |
---|
1476 | 1390 | } |
---|
1477 | 1391 | |
---|
.. | .. |
---|
1485 | 1399 | ret += fprintf(fp, "%sloaded, ", dso__loaded(dso) ? "" : "NOT "); |
---|
1486 | 1400 | ret += dso__fprintf_buildid(dso, fp); |
---|
1487 | 1401 | ret += fprintf(fp, ")\n"); |
---|
1488 | | - for (nd = rb_first(&dso->symbols); nd; nd = rb_next(nd)) { |
---|
| 1402 | + for (nd = rb_first_cached(&dso->symbols); nd; nd = rb_next(nd)) { |
---|
1489 | 1403 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); |
---|
1490 | 1404 | ret += symbol__fprintf(pos, fp); |
---|
1491 | 1405 | } |
---|