brintos

brintos / linux-shallow public Read only

0
0
Text · 6.1 KiB · 5c50309 Raw
247 lines · c
1// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)2/* Copyright (c) 2018 Facebook */3 4#include <string.h>5#include <stdlib.h>6#include <linux/err.h>7#include <linux/bpf.h>8#include "libbpf.h"9#include "libbpf_internal.h"10 11struct bpf_prog_linfo {12	void *raw_linfo;13	void *raw_jited_linfo;14	__u32 *nr_jited_linfo_per_func;15	__u32 *jited_linfo_func_idx;16	__u32 nr_linfo;17	__u32 nr_jited_func;18	__u32 rec_size;19	__u32 jited_rec_size;20};21 22static int dissect_jited_func(struct bpf_prog_linfo *prog_linfo,23			      const __u64 *ksym_func, const __u32 *ksym_len)24{25	__u32 nr_jited_func, nr_linfo;26	const void *raw_jited_linfo;27	const __u64 *jited_linfo;28	__u64 last_jited_linfo;29	/*30	 * Index to raw_jited_linfo:31	 *      i: Index for searching the next ksym_func32	 * prev_i: Index to the last found ksym_func33	 */34	__u32 i, prev_i;35	__u32 f; /* Index to ksym_func */36 37	raw_jited_linfo = prog_linfo->raw_jited_linfo;38	jited_linfo = raw_jited_linfo;39	if (ksym_func[0] != *jited_linfo)40		goto errout;41 42	prog_linfo->jited_linfo_func_idx[0] = 0;43	nr_jited_func = prog_linfo->nr_jited_func;44	nr_linfo = prog_linfo->nr_linfo;45 46	for (prev_i = 0, i = 1, f = 1;47	     i < nr_linfo && f < nr_jited_func;48	     i++) {49		raw_jited_linfo += prog_linfo->jited_rec_size;50		last_jited_linfo = *jited_linfo;51		jited_linfo = raw_jited_linfo;52 53		if (ksym_func[f] == *jited_linfo) {54			prog_linfo->jited_linfo_func_idx[f] = i;55 56			/* Sanity check */57			if (last_jited_linfo - ksym_func[f - 1] + 1 >58			    ksym_len[f - 1])59				goto errout;60 61			prog_linfo->nr_jited_linfo_per_func[f - 1] =62				i - prev_i;63			prev_i = i;64 65			/*66			 * The ksym_func[f] is found in jited_linfo.67			 * Look for the next one.68			 */69			f++;70		} else if (*jited_linfo <= last_jited_linfo) {71			/* Ensure the addr is increasing _within_ a func */72			goto errout;73		}74	}75 76	if (f != nr_jited_func)77		goto errout;78 79	prog_linfo->nr_jited_linfo_per_func[nr_jited_func - 1] =80		nr_linfo - prev_i;81 82	return 0;83 84errout:85	return -EINVAL;86}87 88void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo)89{90	if (!prog_linfo)91		return;92 93	free(prog_linfo->raw_linfo);94	free(prog_linfo->raw_jited_linfo);95	free(prog_linfo->nr_jited_linfo_per_func);96	free(prog_linfo->jited_linfo_func_idx);97	free(prog_linfo);98}99 100struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)101{102	struct bpf_prog_linfo *prog_linfo;103	__u32 nr_linfo, nr_jited_func;104	__u64 data_sz;105 106	nr_linfo = info->nr_line_info;107 108	if (!nr_linfo)109		return errno = EINVAL, NULL;110 111	/*112	 * The min size that bpf_prog_linfo has to access for113	 * searching purpose.114	 */115	if (info->line_info_rec_size <116	    offsetof(struct bpf_line_info, file_name_off))117		return errno = EINVAL, NULL;118 119	prog_linfo = calloc(1, sizeof(*prog_linfo));120	if (!prog_linfo)121		return errno = ENOMEM, NULL;122 123	/* Copy xlated line_info */124	prog_linfo->nr_linfo = nr_linfo;125	prog_linfo->rec_size = info->line_info_rec_size;126	data_sz = (__u64)nr_linfo * prog_linfo->rec_size;127	prog_linfo->raw_linfo = malloc(data_sz);128	if (!prog_linfo->raw_linfo)129		goto err_free;130	memcpy(prog_linfo->raw_linfo, (void *)(long)info->line_info, data_sz);131 132	nr_jited_func = info->nr_jited_ksyms;133	if (!nr_jited_func ||134	    !info->jited_line_info ||135	    info->nr_jited_line_info != nr_linfo ||136	    info->jited_line_info_rec_size < sizeof(__u64) ||137	    info->nr_jited_func_lens != nr_jited_func ||138	    !info->jited_ksyms ||139	    !info->jited_func_lens)140		/* Not enough info to provide jited_line_info */141		return prog_linfo;142 143	/* Copy jited_line_info */144	prog_linfo->nr_jited_func = nr_jited_func;145	prog_linfo->jited_rec_size = info->jited_line_info_rec_size;146	data_sz = (__u64)nr_linfo * prog_linfo->jited_rec_size;147	prog_linfo->raw_jited_linfo = malloc(data_sz);148	if (!prog_linfo->raw_jited_linfo)149		goto err_free;150	memcpy(prog_linfo->raw_jited_linfo,151	       (void *)(long)info->jited_line_info, data_sz);152 153	/* Number of jited_line_info per jited func */154	prog_linfo->nr_jited_linfo_per_func = malloc(nr_jited_func *155						     sizeof(__u32));156	if (!prog_linfo->nr_jited_linfo_per_func)157		goto err_free;158 159	/*160	 * For each jited func,161	 * the start idx to the "linfo" and "jited_linfo" array,162	 */163	prog_linfo->jited_linfo_func_idx = malloc(nr_jited_func *164						  sizeof(__u32));165	if (!prog_linfo->jited_linfo_func_idx)166		goto err_free;167 168	if (dissect_jited_func(prog_linfo,169			       (__u64 *)(long)info->jited_ksyms,170			       (__u32 *)(long)info->jited_func_lens))171		goto err_free;172 173	return prog_linfo;174 175err_free:176	bpf_prog_linfo__free(prog_linfo);177	return errno = EINVAL, NULL;178}179 180const struct bpf_line_info *181bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,182				__u64 addr, __u32 func_idx, __u32 nr_skip)183{184	__u32 jited_rec_size, rec_size, nr_linfo, start, i;185	const void *raw_jited_linfo, *raw_linfo;186	const __u64 *jited_linfo;187 188	if (func_idx >= prog_linfo->nr_jited_func)189		return errno = ENOENT, NULL;190 191	nr_linfo = prog_linfo->nr_jited_linfo_per_func[func_idx];192	if (nr_skip >= nr_linfo)193		return errno = ENOENT, NULL;194 195	start = prog_linfo->jited_linfo_func_idx[func_idx] + nr_skip;196	jited_rec_size = prog_linfo->jited_rec_size;197	raw_jited_linfo = prog_linfo->raw_jited_linfo +198		(start * jited_rec_size);199	jited_linfo = raw_jited_linfo;200	if (addr < *jited_linfo)201		return errno = ENOENT, NULL;202 203	nr_linfo -= nr_skip;204	rec_size = prog_linfo->rec_size;205	raw_linfo = prog_linfo->raw_linfo + (start * rec_size);206	for (i = 0; i < nr_linfo; i++) {207		if (addr < *jited_linfo)208			break;209 210		raw_linfo += rec_size;211		raw_jited_linfo += jited_rec_size;212		jited_linfo = raw_jited_linfo;213	}214 215	return raw_linfo - rec_size;216}217 218const struct bpf_line_info *219bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,220		      __u32 insn_off, __u32 nr_skip)221{222	const struct bpf_line_info *linfo;223	__u32 rec_size, nr_linfo, i;224	const void *raw_linfo;225 226	nr_linfo = prog_linfo->nr_linfo;227	if (nr_skip >= nr_linfo)228		return errno = ENOENT, NULL;229 230	rec_size = prog_linfo->rec_size;231	raw_linfo = prog_linfo->raw_linfo + (nr_skip * rec_size);232	linfo = raw_linfo;233	if (insn_off < linfo->insn_off)234		return errno = ENOENT, NULL;235 236	nr_linfo -= nr_skip;237	for (i = 0; i < nr_linfo; i++) {238		if (insn_off < linfo->insn_off)239			break;240 241		raw_linfo += rec_size;242		linfo = raw_linfo;243	}244 245	return raw_linfo - rec_size;246}247