^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2015, Huawei Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #ifndef __BPF_LOADER_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #define __BPF_LOADER_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <bpf/libbpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) enum bpf_loader_errno {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) __BPF_LOADER_ERRNO__START = __LIBBPF_ERRNO__START - 100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /* Invalid config string */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) BPF_LOADER_ERRNO__CONFIG = __BPF_LOADER_ERRNO__START,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) BPF_LOADER_ERRNO__GROUP, /* Invalid group name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) BPF_LOADER_ERRNO__PROGCONF_TERM,/* Invalid program config term in config string */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) BPF_LOADER_ERRNO__OBJCONF_OPT, /* Invalid object config option */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) BPF_LOADER_ERRNO__OBJCONF_CONF, /* Config value not set (lost '=')) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) BPF_LOADER_ERRNO__OBJCONF_MAP_OPT, /* Invalid object map config option */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST, /* Target map not exist */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE, /* Incorrect value type for map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE, /* Incorrect map type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE, /* Incorrect map key size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE,/* Incorrect map value size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT, /* Event not found for map setting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE, /* Invalid map size for event setting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM, /* Event dimension too large */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH, /* Doesn't support inherit event */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE, /* Wrong event type for map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG, /* Index too large */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) __BPF_LOADER_ERRNO__END,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct evsel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct evlist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct bpf_object;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct parse_events_term;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) typedef int (*bpf_prog_iter_callback_t)(const char *group, const char *event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int fd, struct bpf_object *obj, void *arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #ifdef HAVE_LIBBPF_SUPPORT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct bpf_object *bpf__prepare_load(const char *filename, bool source);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int bpf__strerror_prepare_load(const char *filename, bool source,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) int err, char *buf, size_t size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) const char *name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) void bpf__clear(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) int bpf__probe(struct bpf_object *obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) int bpf__unprobe(struct bpf_object *obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) int bpf__strerror_probe(struct bpf_object *obj, int err,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) char *buf, size_t size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) int bpf__load(struct bpf_object *obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int bpf__strerror_load(struct bpf_object *obj, int err,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) char *buf, size_t size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) int bpf__foreach_event(struct bpf_object *obj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) bpf_prog_iter_callback_t func, void *arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct evlist *evlist, int *error_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) int bpf__strerror_config_obj(struct bpf_object *obj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct parse_events_term *term,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct evlist *evlist,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int *error_pos, int err, char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) size_t size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) int bpf__apply_obj_config(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) int bpf__strerror_apply_obj_config(int err, char *buf, size_t size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int bpf__setup_stdout(struct evlist *evlist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int bpf__strerror_setup_output_event(struct evlist *evlist, int err, char *buf, size_t size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #include "debug.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static inline struct bpf_object *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) bpf__prepare_load(const char *filename __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) bool source __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) pr_debug("ERROR: eBPF object loading is disabled during compiling.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return ERR_PTR(-ENOTSUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static inline struct bpf_object *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) bpf__prepare_load_buffer(void *obj_buf __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) size_t obj_buf_sz __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return ERR_PTR(-ENOTSUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static inline void bpf__clear(void) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0;}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) bpf__foreach_event(struct bpf_object *obj __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) bpf_prog_iter_callback_t func __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) void *arg __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) bpf__config_obj(struct bpf_object *obj __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct parse_events_term *term __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) struct evlist *evlist __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) int *error_pos __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) bpf__apply_obj_config(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) bpf__setup_stdout(struct evlist *evlist __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static inline struct evsel *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) bpf__setup_output_event(struct evlist *evlist __maybe_unused, const char *name __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) __bpf_strerror(char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (!size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) strncpy(buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) "ERROR: eBPF object loading is disabled during compiling.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) buf[size - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static inline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) int bpf__strerror_prepare_load(const char *filename __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) bool source __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) int err __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return __bpf_strerror(buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) int err __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return __bpf_strerror(buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) int err __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return __bpf_strerror(buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct parse_events_term *term __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct evlist *evlist __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) int *error_pos __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) int err __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return __bpf_strerror(buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) bpf__strerror_apply_obj_config(int err __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return __bpf_strerror(buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) bpf__strerror_setup_output_event(struct evlist *evlist __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) int err __maybe_unused, char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return __bpf_strerror(buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static inline int bpf__strerror_setup_stdout(struct evlist *evlist, int err, char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return bpf__strerror_setup_output_event(evlist, err, buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) #endif