0001
0002
0003 #include <errno.h>
0004 #include <linux/err.h>
0005 #include <stdbool.h>
0006 #include <stdio.h>
0007 #include <stdlib.h>
0008 #include <string.h>
0009 #include <unistd.h>
0010
0011 #include <bpf/bpf.h>
0012 #include <bpf/hashmap.h>
0013
0014 #include "main.h"
0015 #include "skeleton/pid_iter.h"
0016
0017 #ifdef BPFTOOL_WITHOUT_SKELETONS
0018
0019 int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type)
0020 {
0021 return -ENOTSUP;
0022 }
0023 void delete_obj_refs_table(struct hashmap *map) {}
0024 void emit_obj_refs_plain(struct hashmap *map, __u32 id, const char *prefix) {}
0025 void emit_obj_refs_json(struct hashmap *map, __u32 id, json_writer_t *json_writer) {}
0026
0027 #else
0028
0029 #include "pid_iter.skel.h"
0030
0031 static void add_ref(struct hashmap *map, struct pid_iter_entry *e)
0032 {
0033 struct hashmap_entry *entry;
0034 struct obj_refs *refs;
0035 struct obj_ref *ref;
0036 int err, i;
0037 void *tmp;
0038
0039 hashmap__for_each_key_entry(map, entry, u32_as_hash_field(e->id)) {
0040 refs = entry->value;
0041
0042 for (i = 0; i < refs->ref_cnt; i++) {
0043 if (refs->refs[i].pid == e->pid)
0044 return;
0045 }
0046
0047 tmp = realloc(refs->refs, (refs->ref_cnt + 1) * sizeof(*ref));
0048 if (!tmp) {
0049 p_err("failed to re-alloc memory for ID %u, PID %d, COMM %s...",
0050 e->id, e->pid, e->comm);
0051 return;
0052 }
0053 refs->refs = tmp;
0054 ref = &refs->refs[refs->ref_cnt];
0055 ref->pid = e->pid;
0056 memcpy(ref->comm, e->comm, sizeof(ref->comm));
0057 refs->ref_cnt++;
0058
0059 return;
0060 }
0061
0062
0063 refs = calloc(1, sizeof(*refs));
0064 if (!refs) {
0065 p_err("failed to alloc memory for ID %u, PID %d, COMM %s...",
0066 e->id, e->pid, e->comm);
0067 return;
0068 }
0069
0070 refs->refs = malloc(sizeof(*refs->refs));
0071 if (!refs->refs) {
0072 free(refs);
0073 p_err("failed to alloc memory for ID %u, PID %d, COMM %s...",
0074 e->id, e->pid, e->comm);
0075 return;
0076 }
0077 ref = &refs->refs[0];
0078 ref->pid = e->pid;
0079 memcpy(ref->comm, e->comm, sizeof(ref->comm));
0080 refs->ref_cnt = 1;
0081 refs->has_bpf_cookie = e->has_bpf_cookie;
0082 refs->bpf_cookie = e->bpf_cookie;
0083
0084 err = hashmap__append(map, u32_as_hash_field(e->id), refs);
0085 if (err)
0086 p_err("failed to append entry to hashmap for ID %u: %s",
0087 e->id, strerror(errno));
0088 }
0089
0090 static int __printf(2, 0)
0091 libbpf_print_none(__maybe_unused enum libbpf_print_level level,
0092 __maybe_unused const char *format,
0093 __maybe_unused va_list args)
0094 {
0095 return 0;
0096 }
0097
0098 int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type)
0099 {
0100 struct pid_iter_entry *e;
0101 char buf[4096 / sizeof(*e) * sizeof(*e)];
0102 struct pid_iter_bpf *skel;
0103 int err, ret, fd = -1, i;
0104 libbpf_print_fn_t default_print;
0105
0106 *map = hashmap__new(hash_fn_for_key_as_id, equal_fn_for_key_as_id, NULL);
0107 if (IS_ERR(*map)) {
0108 p_err("failed to create hashmap for PID references");
0109 return -1;
0110 }
0111 set_max_rlimit();
0112
0113 skel = pid_iter_bpf__open();
0114 if (!skel) {
0115 p_err("failed to open PID iterator skeleton");
0116 return -1;
0117 }
0118
0119 skel->rodata->obj_type = type;
0120
0121
0122
0123
0124 default_print = libbpf_set_print(libbpf_print_none);
0125 err = pid_iter_bpf__load(skel);
0126 libbpf_set_print(default_print);
0127 if (err) {
0128
0129 err = 0;
0130 goto out;
0131 }
0132 err = pid_iter_bpf__attach(skel);
0133 if (err) {
0134
0135 p_err("failed to attach PID iterator: %d", err);
0136 goto out;
0137 }
0138
0139 fd = bpf_iter_create(bpf_link__fd(skel->links.iter));
0140 if (fd < 0) {
0141 err = -errno;
0142 p_err("failed to create PID iterator session: %d", err);
0143 goto out;
0144 }
0145
0146 while (true) {
0147 ret = read(fd, buf, sizeof(buf));
0148 if (ret < 0) {
0149 if (errno == EAGAIN)
0150 continue;
0151 err = -errno;
0152 p_err("failed to read PID iterator output: %d", err);
0153 goto out;
0154 }
0155 if (ret == 0)
0156 break;
0157 if (ret % sizeof(*e)) {
0158 err = -EINVAL;
0159 p_err("invalid PID iterator output format");
0160 goto out;
0161 }
0162 ret /= sizeof(*e);
0163
0164 e = (void *)buf;
0165 for (i = 0; i < ret; i++, e++) {
0166 add_ref(*map, e);
0167 }
0168 }
0169 err = 0;
0170 out:
0171 if (fd >= 0)
0172 close(fd);
0173 pid_iter_bpf__destroy(skel);
0174 return err;
0175 }
0176
0177 void delete_obj_refs_table(struct hashmap *map)
0178 {
0179 struct hashmap_entry *entry;
0180 size_t bkt;
0181
0182 if (!map)
0183 return;
0184
0185 hashmap__for_each_entry(map, entry, bkt) {
0186 struct obj_refs *refs = entry->value;
0187
0188 free(refs->refs);
0189 free(refs);
0190 }
0191
0192 hashmap__free(map);
0193 }
0194
0195 void emit_obj_refs_json(struct hashmap *map, __u32 id,
0196 json_writer_t *json_writer)
0197 {
0198 struct hashmap_entry *entry;
0199
0200 if (hashmap__empty(map))
0201 return;
0202
0203 hashmap__for_each_key_entry(map, entry, u32_as_hash_field(id)) {
0204 struct obj_refs *refs = entry->value;
0205 int i;
0206
0207 if (refs->ref_cnt == 0)
0208 break;
0209
0210 if (refs->has_bpf_cookie)
0211 jsonw_lluint_field(json_writer, "bpf_cookie", refs->bpf_cookie);
0212
0213 jsonw_name(json_writer, "pids");
0214 jsonw_start_array(json_writer);
0215 for (i = 0; i < refs->ref_cnt; i++) {
0216 struct obj_ref *ref = &refs->refs[i];
0217
0218 jsonw_start_object(json_writer);
0219 jsonw_int_field(json_writer, "pid", ref->pid);
0220 jsonw_string_field(json_writer, "comm", ref->comm);
0221 jsonw_end_object(json_writer);
0222 }
0223 jsonw_end_array(json_writer);
0224 break;
0225 }
0226 }
0227
0228 void emit_obj_refs_plain(struct hashmap *map, __u32 id, const char *prefix)
0229 {
0230 struct hashmap_entry *entry;
0231
0232 if (hashmap__empty(map))
0233 return;
0234
0235 hashmap__for_each_key_entry(map, entry, u32_as_hash_field(id)) {
0236 struct obj_refs *refs = entry->value;
0237 int i;
0238
0239 if (refs->ref_cnt == 0)
0240 break;
0241
0242 if (refs->has_bpf_cookie)
0243 printf("\n\tbpf_cookie %llu", (unsigned long long) refs->bpf_cookie);
0244
0245 printf("%s", prefix);
0246 for (i = 0; i < refs->ref_cnt; i++) {
0247 struct obj_ref *ref = &refs->refs[i];
0248
0249 printf("%s%s(%d)", i == 0 ? "" : ", ", ref->comm, ref->pid);
0250 }
0251 break;
0252 }
0253 }
0254
0255
0256 #endif