linux/tools/bpf/bpftool/pids.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2/* Copyright (C) 2020 Facebook */
   3#include <errno.h>
   4#include <linux/err.h>
   5#include <stdbool.h>
   6#include <stdio.h>
   7#include <stdlib.h>
   8#include <string.h>
   9#include <unistd.h>
  10
  11#include <bpf/bpf.h>
  12#include <bpf/hashmap.h>
  13
  14#include "main.h"
  15#include "skeleton/pid_iter.h"
  16
  17#ifdef BPFTOOL_WITHOUT_SKELETONS
  18
  19int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type)
  20{
  21        return -ENOTSUP;
  22}
  23void delete_obj_refs_table(struct hashmap *map) {}
  24void emit_obj_refs_plain(struct hashmap *map, __u32 id, const char *prefix) {}
  25void emit_obj_refs_json(struct hashmap *map, __u32 id, json_writer_t *json_writer) {}
  26
  27#else /* BPFTOOL_WITHOUT_SKELETONS */
  28
  29#include "pid_iter.skel.h"
  30
  31static void add_ref(struct hashmap *map, struct pid_iter_entry *e)
  32{
  33        struct hashmap_entry *entry;
  34        struct obj_refs *refs;
  35        struct obj_ref *ref;
  36        int err, i;
  37        void *tmp;
  38
  39        hashmap__for_each_key_entry(map, entry, u32_as_hash_field(e->id)) {
  40                refs = entry->value;
  41
  42                for (i = 0; i < refs->ref_cnt; i++) {
  43                        if (refs->refs[i].pid == e->pid)
  44                                return;
  45                }
  46
  47                tmp = realloc(refs->refs, (refs->ref_cnt + 1) * sizeof(*ref));
  48                if (!tmp) {
  49                        p_err("failed to re-alloc memory for ID %u, PID %d, COMM %s...",
  50                              e->id, e->pid, e->comm);
  51                        return;
  52                }
  53                refs->refs = tmp;
  54                ref = &refs->refs[refs->ref_cnt];
  55                ref->pid = e->pid;
  56                memcpy(ref->comm, e->comm, sizeof(ref->comm));
  57                refs->ref_cnt++;
  58
  59                return;
  60        }
  61
  62        /* new ref */
  63        refs = calloc(1, sizeof(*refs));
  64        if (!refs) {
  65                p_err("failed to alloc memory for ID %u, PID %d, COMM %s...",
  66                      e->id, e->pid, e->comm);
  67                return;
  68        }
  69
  70        refs->refs = malloc(sizeof(*refs->refs));
  71        if (!refs->refs) {
  72                free(refs);
  73                p_err("failed to alloc memory for ID %u, PID %d, COMM %s...",
  74                      e->id, e->pid, e->comm);
  75                return;
  76        }
  77        ref = &refs->refs[0];
  78        ref->pid = e->pid;
  79        memcpy(ref->comm, e->comm, sizeof(ref->comm));
  80        refs->ref_cnt = 1;
  81        refs->has_bpf_cookie = e->has_bpf_cookie;
  82        refs->bpf_cookie = e->bpf_cookie;
  83
  84        err = hashmap__append(map, u32_as_hash_field(e->id), refs);
  85        if (err)
  86                p_err("failed to append entry to hashmap for ID %u: %s",
  87                      e->id, strerror(errno));
  88}
  89
  90static int __printf(2, 0)
  91libbpf_print_none(__maybe_unused enum libbpf_print_level level,
  92                  __maybe_unused const char *format,
  93                  __maybe_unused va_list args)
  94{
  95        return 0;
  96}
  97
  98int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type)
  99{
 100        struct pid_iter_entry *e;
 101        char buf[4096 / sizeof(*e) * sizeof(*e)];
 102        struct pid_iter_bpf *skel;
 103        int err, ret, fd = -1, i;
 104        libbpf_print_fn_t default_print;
 105
 106        *map = hashmap__new(hash_fn_for_key_as_id, equal_fn_for_key_as_id, NULL);
 107        if (IS_ERR(*map)) {
 108                p_err("failed to create hashmap for PID references");
 109                return -1;
 110        }
 111        set_max_rlimit();
 112
 113        skel = pid_iter_bpf__open();
 114        if (!skel) {
 115                p_err("failed to open PID iterator skeleton");
 116                return -1;
 117        }
 118
 119        skel->rodata->obj_type = type;
 120
 121        /* we don't want output polluted with libbpf errors if bpf_iter is not
 122         * supported
 123         */
 124        default_print = libbpf_set_print(libbpf_print_none);
 125        err = pid_iter_bpf__load(skel);
 126        libbpf_set_print(default_print);
 127        if (err) {
 128                /* too bad, kernel doesn't support BPF iterators yet */
 129                err = 0;
 130                goto out;
 131        }
 132        err = pid_iter_bpf__attach(skel);
 133        if (err) {
 134                /* if we loaded above successfully, attach has to succeed */
 135                p_err("failed to attach PID iterator: %d", err);
 136                goto out;
 137        }
 138
 139        fd = bpf_iter_create(bpf_link__fd(skel->links.iter));
 140        if (fd < 0) {
 141                err = -errno;
 142                p_err("failed to create PID iterator session: %d", err);
 143                goto out;
 144        }
 145
 146        while (true) {
 147                ret = read(fd, buf, sizeof(buf));
 148                if (ret < 0) {
 149                        if (errno == EAGAIN)
 150                                continue;
 151                        err = -errno;
 152                        p_err("failed to read PID iterator output: %d", err);
 153                        goto out;
 154                }
 155                if (ret == 0)
 156                        break;
 157                if (ret % sizeof(*e)) {
 158                        err = -EINVAL;
 159                        p_err("invalid PID iterator output format");
 160                        goto out;
 161                }
 162                ret /= sizeof(*e);
 163
 164                e = (void *)buf;
 165                for (i = 0; i < ret; i++, e++) {
 166                        add_ref(*map, e);
 167                }
 168        }
 169        err = 0;
 170out:
 171        if (fd >= 0)
 172                close(fd);
 173        pid_iter_bpf__destroy(skel);
 174        return err;
 175}
 176
 177void delete_obj_refs_table(struct hashmap *map)
 178{
 179        struct hashmap_entry *entry;
 180        size_t bkt;
 181
 182        if (!map)
 183                return;
 184
 185        hashmap__for_each_entry(map, entry, bkt) {
 186                struct obj_refs *refs = entry->value;
 187
 188                free(refs->refs);
 189                free(refs);
 190        }
 191
 192        hashmap__free(map);
 193}
 194
 195void emit_obj_refs_json(struct hashmap *map, __u32 id,
 196                        json_writer_t *json_writer)
 197{
 198        struct hashmap_entry *entry;
 199
 200        if (hashmap__empty(map))
 201                return;
 202
 203        hashmap__for_each_key_entry(map, entry, u32_as_hash_field(id)) {
 204                struct obj_refs *refs = entry->value;
 205                int i;
 206
 207                if (refs->ref_cnt == 0)
 208                        break;
 209
 210                if (refs->has_bpf_cookie)
 211                        jsonw_lluint_field(json_writer, "bpf_cookie", refs->bpf_cookie);
 212
 213                jsonw_name(json_writer, "pids");
 214                jsonw_start_array(json_writer);
 215                for (i = 0; i < refs->ref_cnt; i++) {
 216                        struct obj_ref *ref = &refs->refs[i];
 217
 218                        jsonw_start_object(json_writer);
 219                        jsonw_int_field(json_writer, "pid", ref->pid);
 220                        jsonw_string_field(json_writer, "comm", ref->comm);
 221                        jsonw_end_object(json_writer);
 222                }
 223                jsonw_end_array(json_writer);
 224                break;
 225        }
 226}
 227
 228void emit_obj_refs_plain(struct hashmap *map, __u32 id, const char *prefix)
 229{
 230        struct hashmap_entry *entry;
 231
 232        if (hashmap__empty(map))
 233                return;
 234
 235        hashmap__for_each_key_entry(map, entry, u32_as_hash_field(id)) {
 236                struct obj_refs *refs = entry->value;
 237                int i;
 238
 239                if (refs->ref_cnt == 0)
 240                        break;
 241
 242                if (refs->has_bpf_cookie)
 243                        printf("\n\tbpf_cookie %llu", (unsigned long long) refs->bpf_cookie);
 244
 245                printf("%s", prefix);
 246                for (i = 0; i < refs->ref_cnt; i++) {
 247                        struct obj_ref *ref = &refs->refs[i];
 248
 249                        printf("%s%s(%d)", i == 0 ? "" : ", ", ref->comm, ref->pid);
 250                }
 251                break;
 252        }
 253}
 254
 255
 256#endif
 257