0001
0002
0003
0004 #include <string.h>
0005 #include <stdlib.h>
0006 #include <linux/err.h>
0007 #include <linux/bpf.h>
0008 #include "libbpf.h"
0009 #include "libbpf_internal.h"
0010
0011 struct bpf_prog_linfo {
0012 void *raw_linfo;
0013 void *raw_jited_linfo;
0014 __u32 *nr_jited_linfo_per_func;
0015 __u32 *jited_linfo_func_idx;
0016 __u32 nr_linfo;
0017 __u32 nr_jited_func;
0018 __u32 rec_size;
0019 __u32 jited_rec_size;
0020 };
0021
0022 static int dissect_jited_func(struct bpf_prog_linfo *prog_linfo,
0023 const __u64 *ksym_func, const __u32 *ksym_len)
0024 {
0025 __u32 nr_jited_func, nr_linfo;
0026 const void *raw_jited_linfo;
0027 const __u64 *jited_linfo;
0028 __u64 last_jited_linfo;
0029
0030
0031
0032
0033
0034 __u32 i, prev_i;
0035 __u32 f;
0036
0037 raw_jited_linfo = prog_linfo->raw_jited_linfo;
0038 jited_linfo = raw_jited_linfo;
0039 if (ksym_func[0] != *jited_linfo)
0040 goto errout;
0041
0042 prog_linfo->jited_linfo_func_idx[0] = 0;
0043 nr_jited_func = prog_linfo->nr_jited_func;
0044 nr_linfo = prog_linfo->nr_linfo;
0045
0046 for (prev_i = 0, i = 1, f = 1;
0047 i < nr_linfo && f < nr_jited_func;
0048 i++) {
0049 raw_jited_linfo += prog_linfo->jited_rec_size;
0050 last_jited_linfo = *jited_linfo;
0051 jited_linfo = raw_jited_linfo;
0052
0053 if (ksym_func[f] == *jited_linfo) {
0054 prog_linfo->jited_linfo_func_idx[f] = i;
0055
0056
0057 if (last_jited_linfo - ksym_func[f - 1] + 1 >
0058 ksym_len[f - 1])
0059 goto errout;
0060
0061 prog_linfo->nr_jited_linfo_per_func[f - 1] =
0062 i - prev_i;
0063 prev_i = i;
0064
0065
0066
0067
0068
0069 f++;
0070 } else if (*jited_linfo <= last_jited_linfo) {
0071
0072 goto errout;
0073 }
0074 }
0075
0076 if (f != nr_jited_func)
0077 goto errout;
0078
0079 prog_linfo->nr_jited_linfo_per_func[nr_jited_func - 1] =
0080 nr_linfo - prev_i;
0081
0082 return 0;
0083
0084 errout:
0085 return -EINVAL;
0086 }
0087
0088 void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo)
0089 {
0090 if (!prog_linfo)
0091 return;
0092
0093 free(prog_linfo->raw_linfo);
0094 free(prog_linfo->raw_jited_linfo);
0095 free(prog_linfo->nr_jited_linfo_per_func);
0096 free(prog_linfo->jited_linfo_func_idx);
0097 free(prog_linfo);
0098 }
0099
0100 struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
0101 {
0102 struct bpf_prog_linfo *prog_linfo;
0103 __u32 nr_linfo, nr_jited_func;
0104 __u64 data_sz;
0105
0106 nr_linfo = info->nr_line_info;
0107
0108 if (!nr_linfo)
0109 return errno = EINVAL, NULL;
0110
0111
0112
0113
0114
0115 if (info->line_info_rec_size <
0116 offsetof(struct bpf_line_info, file_name_off))
0117 return errno = EINVAL, NULL;
0118
0119 prog_linfo = calloc(1, sizeof(*prog_linfo));
0120 if (!prog_linfo)
0121 return errno = ENOMEM, NULL;
0122
0123
0124 prog_linfo->nr_linfo = nr_linfo;
0125 prog_linfo->rec_size = info->line_info_rec_size;
0126 data_sz = (__u64)nr_linfo * prog_linfo->rec_size;
0127 prog_linfo->raw_linfo = malloc(data_sz);
0128 if (!prog_linfo->raw_linfo)
0129 goto err_free;
0130 memcpy(prog_linfo->raw_linfo, (void *)(long)info->line_info, data_sz);
0131
0132 nr_jited_func = info->nr_jited_ksyms;
0133 if (!nr_jited_func ||
0134 !info->jited_line_info ||
0135 info->nr_jited_line_info != nr_linfo ||
0136 info->jited_line_info_rec_size < sizeof(__u64) ||
0137 info->nr_jited_func_lens != nr_jited_func ||
0138 !info->jited_ksyms ||
0139 !info->jited_func_lens)
0140
0141 return prog_linfo;
0142
0143
0144 prog_linfo->nr_jited_func = nr_jited_func;
0145 prog_linfo->jited_rec_size = info->jited_line_info_rec_size;
0146 data_sz = (__u64)nr_linfo * prog_linfo->jited_rec_size;
0147 prog_linfo->raw_jited_linfo = malloc(data_sz);
0148 if (!prog_linfo->raw_jited_linfo)
0149 goto err_free;
0150 memcpy(prog_linfo->raw_jited_linfo,
0151 (void *)(long)info->jited_line_info, data_sz);
0152
0153
0154 prog_linfo->nr_jited_linfo_per_func = malloc(nr_jited_func *
0155 sizeof(__u32));
0156 if (!prog_linfo->nr_jited_linfo_per_func)
0157 goto err_free;
0158
0159
0160
0161
0162
0163 prog_linfo->jited_linfo_func_idx = malloc(nr_jited_func *
0164 sizeof(__u32));
0165 if (!prog_linfo->jited_linfo_func_idx)
0166 goto err_free;
0167
0168 if (dissect_jited_func(prog_linfo,
0169 (__u64 *)(long)info->jited_ksyms,
0170 (__u32 *)(long)info->jited_func_lens))
0171 goto err_free;
0172
0173 return prog_linfo;
0174
0175 err_free:
0176 bpf_prog_linfo__free(prog_linfo);
0177 return errno = EINVAL, NULL;
0178 }
0179
0180 const struct bpf_line_info *
0181 bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
0182 __u64 addr, __u32 func_idx, __u32 nr_skip)
0183 {
0184 __u32 jited_rec_size, rec_size, nr_linfo, start, i;
0185 const void *raw_jited_linfo, *raw_linfo;
0186 const __u64 *jited_linfo;
0187
0188 if (func_idx >= prog_linfo->nr_jited_func)
0189 return errno = ENOENT, NULL;
0190
0191 nr_linfo = prog_linfo->nr_jited_linfo_per_func[func_idx];
0192 if (nr_skip >= nr_linfo)
0193 return errno = ENOENT, NULL;
0194
0195 start = prog_linfo->jited_linfo_func_idx[func_idx] + nr_skip;
0196 jited_rec_size = prog_linfo->jited_rec_size;
0197 raw_jited_linfo = prog_linfo->raw_jited_linfo +
0198 (start * jited_rec_size);
0199 jited_linfo = raw_jited_linfo;
0200 if (addr < *jited_linfo)
0201 return errno = ENOENT, NULL;
0202
0203 nr_linfo -= nr_skip;
0204 rec_size = prog_linfo->rec_size;
0205 raw_linfo = prog_linfo->raw_linfo + (start * rec_size);
0206 for (i = 0; i < nr_linfo; i++) {
0207 if (addr < *jited_linfo)
0208 break;
0209
0210 raw_linfo += rec_size;
0211 raw_jited_linfo += jited_rec_size;
0212 jited_linfo = raw_jited_linfo;
0213 }
0214
0215 return raw_linfo - rec_size;
0216 }
0217
0218 const struct bpf_line_info *
0219 bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
0220 __u32 insn_off, __u32 nr_skip)
0221 {
0222 const struct bpf_line_info *linfo;
0223 __u32 rec_size, nr_linfo, i;
0224 const void *raw_linfo;
0225
0226 nr_linfo = prog_linfo->nr_linfo;
0227 if (nr_skip >= nr_linfo)
0228 return errno = ENOENT, NULL;
0229
0230 rec_size = prog_linfo->rec_size;
0231 raw_linfo = prog_linfo->raw_linfo + (nr_skip * rec_size);
0232 linfo = raw_linfo;
0233 if (insn_off < linfo->insn_off)
0234 return errno = ENOENT, NULL;
0235
0236 nr_linfo -= nr_skip;
0237 for (i = 0; i < nr_linfo; i++) {
0238 if (insn_off < linfo->insn_off)
0239 break;
0240
0241 raw_linfo += rec_size;
0242 linfo = raw_linfo;
0243 }
0244
0245 return raw_linfo - rec_size;
0246 }