Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2020 Facebook */
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 /* BPFTOOL_WITHOUT_SKELETONS */
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     /* new ref */
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     /* we don't want output polluted with libbpf errors if bpf_iter is not
0122      * supported
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         /* too bad, kernel doesn't support BPF iterators yet */
0129         err = 0;
0130         goto out;
0131     }
0132     err = pid_iter_bpf__attach(skel);
0133     if (err) {
0134         /* if we loaded above successfully, attach has to succeed */
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