18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2019 Facebook 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <stdint.h> 58c2ecf20Sopenharmony_ci#include <stddef.h> 68c2ecf20Sopenharmony_ci#include <stdbool.h> 78c2ecf20Sopenharmony_ci#include <linux/bpf.h> 88c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 98c2ecf20Sopenharmony_ci#include <linux/sched.h> 108c2ecf20Sopenharmony_ci#include <linux/types.h> 118c2ecf20Sopenharmony_ci#include <bpf/bpf_helpers.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_citypedef uint32_t pid_t; 148c2ecf20Sopenharmony_cistruct task_struct {}; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define TASK_COMM_LEN 16 178c2ecf20Sopenharmony_ci#define PERF_MAX_STACK_DEPTH 127 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define STROBE_TYPE_INVALID 0 208c2ecf20Sopenharmony_ci#define STROBE_TYPE_INT 1 218c2ecf20Sopenharmony_ci#define STROBE_TYPE_STR 2 228c2ecf20Sopenharmony_ci#define STROBE_TYPE_MAP 3 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define STACK_TABLE_EPOCH_SHIFT 20 258c2ecf20Sopenharmony_ci#define STROBE_MAX_STR_LEN 1 268c2ecf20Sopenharmony_ci#define STROBE_MAX_CFGS 32 278c2ecf20Sopenharmony_ci#define STROBE_MAX_PAYLOAD \ 288c2ecf20Sopenharmony_ci (STROBE_MAX_STRS * STROBE_MAX_STR_LEN + \ 298c2ecf20Sopenharmony_ci STROBE_MAX_MAPS * (1 + STROBE_MAX_MAP_ENTRIES * 2) * STROBE_MAX_STR_LEN) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct strobe_value_header { 328c2ecf20Sopenharmony_ci /* 338c2ecf20Sopenharmony_ci * meaning depends on type: 348c2ecf20Sopenharmony_ci * 1. int: 0, if value not set, 1 otherwise 358c2ecf20Sopenharmony_ci * 2. str: 1 always, whether value is set or not is determined by ptr 368c2ecf20Sopenharmony_ci * 3. map: 1 always, pointer points to additional struct with number 378c2ecf20Sopenharmony_ci * of entries (up to STROBE_MAX_MAP_ENTRIES) 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci uint16_t len; 408c2ecf20Sopenharmony_ci /* 418c2ecf20Sopenharmony_ci * _reserved might be used for some future fields/flags, but we always 428c2ecf20Sopenharmony_ci * want to keep strobe_value_header to be 8 bytes, so BPF can read 16 438c2ecf20Sopenharmony_ci * bytes in one go and get both header and value 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci uint8_t _reserved[6]; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * strobe_value_generic is used from BPF probe only, but needs to be a union 508c2ecf20Sopenharmony_ci * of strobe_value_int/strobe_value_str/strobe_value_map 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_cistruct strobe_value_generic { 538c2ecf20Sopenharmony_ci struct strobe_value_header header; 548c2ecf20Sopenharmony_ci union { 558c2ecf20Sopenharmony_ci int64_t val; 568c2ecf20Sopenharmony_ci void *ptr; 578c2ecf20Sopenharmony_ci }; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct strobe_value_int { 618c2ecf20Sopenharmony_ci struct strobe_value_header header; 628c2ecf20Sopenharmony_ci int64_t value; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct strobe_value_str { 668c2ecf20Sopenharmony_ci struct strobe_value_header header; 678c2ecf20Sopenharmony_ci const char* value; 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistruct strobe_value_map { 718c2ecf20Sopenharmony_ci struct strobe_value_header header; 728c2ecf20Sopenharmony_ci const struct strobe_map_raw* value; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistruct strobe_map_entry { 768c2ecf20Sopenharmony_ci const char* key; 778c2ecf20Sopenharmony_ci const char* val; 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * Map of C-string key/value pairs with fixed maximum capacity. Each map has 828c2ecf20Sopenharmony_ci * corresponding int64 ID, which application can use (or ignore) in whatever 838c2ecf20Sopenharmony_ci * way appropriate. Map is "write-only", there is no way to get data out of 848c2ecf20Sopenharmony_ci * map. Map is intended to be used to provide metadata for profilers and is 858c2ecf20Sopenharmony_ci * not to be used for internal in-app communication. All methods are 868c2ecf20Sopenharmony_ci * thread-safe. 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_cistruct strobe_map_raw { 898c2ecf20Sopenharmony_ci /* 908c2ecf20Sopenharmony_ci * general purpose unique ID that's up to application to decide 918c2ecf20Sopenharmony_ci * whether and how to use; for request metadata use case id is unique 928c2ecf20Sopenharmony_ci * request ID that's used to match metadata with stack traces on 938c2ecf20Sopenharmony_ci * Strobelight backend side 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci int64_t id; 968c2ecf20Sopenharmony_ci /* number of used entries in map */ 978c2ecf20Sopenharmony_ci int64_t cnt; 988c2ecf20Sopenharmony_ci /* 998c2ecf20Sopenharmony_ci * having volatile doesn't change anything on BPF side, but clang 1008c2ecf20Sopenharmony_ci * emits warnings for passing `volatile const char *` into 1018c2ecf20Sopenharmony_ci * bpf_probe_read_user_str that expects just `const char *` 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci const char* tag; 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * key/value entries, each consisting of 2 pointers to key and value 1068c2ecf20Sopenharmony_ci * C strings 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci struct strobe_map_entry entries[STROBE_MAX_MAP_ENTRIES]; 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* Following values define supported values of TLS mode */ 1128c2ecf20Sopenharmony_ci#define TLS_NOT_SET -1 1138c2ecf20Sopenharmony_ci#define TLS_LOCAL_EXEC 0 1148c2ecf20Sopenharmony_ci#define TLS_IMM_EXEC 1 1158c2ecf20Sopenharmony_ci#define TLS_GENERAL_DYN 2 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* 1188c2ecf20Sopenharmony_ci * structure that universally represents TLS location (both for static 1198c2ecf20Sopenharmony_ci * executables and shared libraries) 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_cistruct strobe_value_loc { 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * tls_mode defines what TLS mode was used for particular metavariable: 1248c2ecf20Sopenharmony_ci * - -1 (TLS_NOT_SET) - no metavariable; 1258c2ecf20Sopenharmony_ci * - 0 (TLS_LOCAL_EXEC) - Local Executable mode; 1268c2ecf20Sopenharmony_ci * - 1 (TLS_IMM_EXEC) - Immediate Executable mode; 1278c2ecf20Sopenharmony_ci * - 2 (TLS_GENERAL_DYN) - General Dynamic mode; 1288c2ecf20Sopenharmony_ci * Local Dynamic mode is not yet supported, because never seen in 1298c2ecf20Sopenharmony_ci * practice. Mode defines how offset field is interpreted. See 1308c2ecf20Sopenharmony_ci * calc_location() in below for details. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci int64_t tls_mode; 1338c2ecf20Sopenharmony_ci /* 1348c2ecf20Sopenharmony_ci * TLS_LOCAL_EXEC: offset from thread pointer (fs:0 for x86-64, 1358c2ecf20Sopenharmony_ci * tpidr_el0 for aarch64). 1368c2ecf20Sopenharmony_ci * TLS_IMM_EXEC: absolute address of GOT entry containing offset 1378c2ecf20Sopenharmony_ci * from thread pointer; 1388c2ecf20Sopenharmony_ci * TLS_GENERAL_DYN: absolute addres of double GOT entry 1398c2ecf20Sopenharmony_ci * containing tls_index_t struct; 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci int64_t offset; 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistruct strobemeta_cfg { 1458c2ecf20Sopenharmony_ci int64_t req_meta_idx; 1468c2ecf20Sopenharmony_ci struct strobe_value_loc int_locs[STROBE_MAX_INTS]; 1478c2ecf20Sopenharmony_ci struct strobe_value_loc str_locs[STROBE_MAX_STRS]; 1488c2ecf20Sopenharmony_ci struct strobe_value_loc map_locs[STROBE_MAX_MAPS]; 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistruct strobe_map_descr { 1528c2ecf20Sopenharmony_ci uint64_t id; 1538c2ecf20Sopenharmony_ci int16_t tag_len; 1548c2ecf20Sopenharmony_ci /* 1558c2ecf20Sopenharmony_ci * cnt <0 - map value isn't set; 1568c2ecf20Sopenharmony_ci * 0 - map has id set, but no key/value entries 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ci int16_t cnt; 1598c2ecf20Sopenharmony_ci /* 1608c2ecf20Sopenharmony_ci * both key_lens[i] and val_lens[i] should be >0 for present key/value 1618c2ecf20Sopenharmony_ci * entry 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci uint16_t key_lens[STROBE_MAX_MAP_ENTRIES]; 1648c2ecf20Sopenharmony_ci uint16_t val_lens[STROBE_MAX_MAP_ENTRIES]; 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistruct strobemeta_payload { 1688c2ecf20Sopenharmony_ci /* req_id has valid request ID, if req_meta_valid == 1 */ 1698c2ecf20Sopenharmony_ci int64_t req_id; 1708c2ecf20Sopenharmony_ci uint8_t req_meta_valid; 1718c2ecf20Sopenharmony_ci /* 1728c2ecf20Sopenharmony_ci * mask has Nth bit set to 1, if Nth metavar was present and 1738c2ecf20Sopenharmony_ci * successfully read 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci uint64_t int_vals_set_mask; 1768c2ecf20Sopenharmony_ci int64_t int_vals[STROBE_MAX_INTS]; 1778c2ecf20Sopenharmony_ci /* len is >0 for present values */ 1788c2ecf20Sopenharmony_ci uint16_t str_lens[STROBE_MAX_STRS]; 1798c2ecf20Sopenharmony_ci /* if map_descrs[i].cnt == -1, metavar is not present/set */ 1808c2ecf20Sopenharmony_ci struct strobe_map_descr map_descrs[STROBE_MAX_MAPS]; 1818c2ecf20Sopenharmony_ci /* 1828c2ecf20Sopenharmony_ci * payload has compactly packed values of str and map variables in the 1838c2ecf20Sopenharmony_ci * form: strval1\0strval2\0map1key1\0map1val1\0map2key1\0map2val1\0 1848c2ecf20Sopenharmony_ci * (and so on); str_lens[i], key_lens[i] and val_lens[i] determines 1858c2ecf20Sopenharmony_ci * value length 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci char payload[STROBE_MAX_PAYLOAD]; 1888c2ecf20Sopenharmony_ci}; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistruct strobelight_bpf_sample { 1918c2ecf20Sopenharmony_ci uint64_t ktime; 1928c2ecf20Sopenharmony_ci char comm[TASK_COMM_LEN]; 1938c2ecf20Sopenharmony_ci pid_t pid; 1948c2ecf20Sopenharmony_ci int user_stack_id; 1958c2ecf20Sopenharmony_ci int kernel_stack_id; 1968c2ecf20Sopenharmony_ci int has_meta; 1978c2ecf20Sopenharmony_ci struct strobemeta_payload metadata; 1988c2ecf20Sopenharmony_ci /* 1998c2ecf20Sopenharmony_ci * makes it possible to pass (<real payload size> + 1) as data size to 2008c2ecf20Sopenharmony_ci * perf_submit() to avoid perf_submit's paranoia about passing zero as 2018c2ecf20Sopenharmony_ci * size, as it deduces that <real payload size> might be 2028c2ecf20Sopenharmony_ci * **theoretically** zero 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci char dummy_safeguard; 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistruct { 2088c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); 2098c2ecf20Sopenharmony_ci __uint(max_entries, 32); 2108c2ecf20Sopenharmony_ci __uint(key_size, sizeof(int)); 2118c2ecf20Sopenharmony_ci __uint(value_size, sizeof(int)); 2128c2ecf20Sopenharmony_ci} samples SEC(".maps"); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistruct { 2158c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_STACK_TRACE); 2168c2ecf20Sopenharmony_ci __uint(max_entries, 16); 2178c2ecf20Sopenharmony_ci __uint(key_size, sizeof(uint32_t)); 2188c2ecf20Sopenharmony_ci __uint(value_size, sizeof(uint64_t) * PERF_MAX_STACK_DEPTH); 2198c2ecf20Sopenharmony_ci} stacks_0 SEC(".maps"); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistruct { 2228c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_STACK_TRACE); 2238c2ecf20Sopenharmony_ci __uint(max_entries, 16); 2248c2ecf20Sopenharmony_ci __uint(key_size, sizeof(uint32_t)); 2258c2ecf20Sopenharmony_ci __uint(value_size, sizeof(uint64_t) * PERF_MAX_STACK_DEPTH); 2268c2ecf20Sopenharmony_ci} stacks_1 SEC(".maps"); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistruct { 2298c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 2308c2ecf20Sopenharmony_ci __uint(max_entries, 1); 2318c2ecf20Sopenharmony_ci __type(key, uint32_t); 2328c2ecf20Sopenharmony_ci __type(value, struct strobelight_bpf_sample); 2338c2ecf20Sopenharmony_ci} sample_heap SEC(".maps"); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistruct { 2368c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 2378c2ecf20Sopenharmony_ci __uint(max_entries, STROBE_MAX_CFGS); 2388c2ecf20Sopenharmony_ci __type(key, pid_t); 2398c2ecf20Sopenharmony_ci __type(value, struct strobemeta_cfg); 2408c2ecf20Sopenharmony_ci} strobemeta_cfgs SEC(".maps"); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* Type for the dtv. */ 2438c2ecf20Sopenharmony_ci/* https://github.com/lattera/glibc/blob/master/nptl/sysdeps/x86_64/tls.h#L34 */ 2448c2ecf20Sopenharmony_citypedef union dtv { 2458c2ecf20Sopenharmony_ci size_t counter; 2468c2ecf20Sopenharmony_ci struct { 2478c2ecf20Sopenharmony_ci void* val; 2488c2ecf20Sopenharmony_ci bool is_static; 2498c2ecf20Sopenharmony_ci } pointer; 2508c2ecf20Sopenharmony_ci} dtv_t; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/* Partial definition for tcbhead_t */ 2538c2ecf20Sopenharmony_ci/* https://github.com/bminor/glibc/blob/master/sysdeps/x86_64/nptl/tls.h#L42 */ 2548c2ecf20Sopenharmony_cistruct tcbhead { 2558c2ecf20Sopenharmony_ci void* tcb; 2568c2ecf20Sopenharmony_ci dtv_t* dtv; 2578c2ecf20Sopenharmony_ci}; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci/* 2608c2ecf20Sopenharmony_ci * TLS module/offset information for shared library case. 2618c2ecf20Sopenharmony_ci * For x86-64, this is mapped onto two entries in GOT. 2628c2ecf20Sopenharmony_ci * For aarch64, this is pointed to by second GOT entry. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_cistruct tls_index { 2658c2ecf20Sopenharmony_ci uint64_t module; 2668c2ecf20Sopenharmony_ci uint64_t offset; 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci#ifdef SUBPROGS 2708c2ecf20Sopenharmony_ci__noinline 2718c2ecf20Sopenharmony_ci#else 2728c2ecf20Sopenharmony_ci__always_inline 2738c2ecf20Sopenharmony_ci#endif 2748c2ecf20Sopenharmony_cistatic void *calc_location(struct strobe_value_loc *loc, void *tls_base) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci /* 2778c2ecf20Sopenharmony_ci * tls_mode value is: 2788c2ecf20Sopenharmony_ci * - -1 (TLS_NOT_SET), if no metavar is present; 2798c2ecf20Sopenharmony_ci * - 0 (TLS_LOCAL_EXEC), if metavar uses Local Executable mode of TLS 2808c2ecf20Sopenharmony_ci * (offset from fs:0 for x86-64 or tpidr_el0 for aarch64); 2818c2ecf20Sopenharmony_ci * - 1 (TLS_IMM_EXEC), if metavar uses Immediate Executable mode of TLS; 2828c2ecf20Sopenharmony_ci * - 2 (TLS_GENERAL_DYN), if metavar uses General Dynamic mode of TLS; 2838c2ecf20Sopenharmony_ci * This schema allows to use something like: 2848c2ecf20Sopenharmony_ci * (tls_mode + 1) * (tls_base + offset) 2858c2ecf20Sopenharmony_ci * to get NULL for "no metavar" location, or correct pointer for local 2868c2ecf20Sopenharmony_ci * executable mode without doing extra ifs. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci if (loc->tls_mode <= TLS_LOCAL_EXEC) { 2898c2ecf20Sopenharmony_ci /* static executable is simple, we just have offset from 2908c2ecf20Sopenharmony_ci * tls_base */ 2918c2ecf20Sopenharmony_ci void *addr = tls_base + loc->offset; 2928c2ecf20Sopenharmony_ci /* multiply by (tls_mode + 1) to get NULL, if we have no 2938c2ecf20Sopenharmony_ci * metavar in this slot */ 2948c2ecf20Sopenharmony_ci return (void *)((loc->tls_mode + 1) * (int64_t)addr); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci /* 2978c2ecf20Sopenharmony_ci * Other modes are more complicated, we need to jump through few hoops. 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * For immediate executable mode (currently supported only for aarch64): 3008c2ecf20Sopenharmony_ci * - loc->offset is pointing to a GOT entry containing fixed offset 3018c2ecf20Sopenharmony_ci * relative to tls_base; 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci * For general dynamic mode: 3048c2ecf20Sopenharmony_ci * - loc->offset is pointing to a beginning of double GOT entries; 3058c2ecf20Sopenharmony_ci * - (for aarch64 only) second entry points to tls_index_t struct; 3068c2ecf20Sopenharmony_ci * - (for x86-64 only) two GOT entries are already tls_index_t; 3078c2ecf20Sopenharmony_ci * - tls_index_t->module is used to find start of TLS section in 3088c2ecf20Sopenharmony_ci * which variable resides; 3098c2ecf20Sopenharmony_ci * - tls_index_t->offset provides offset within that TLS section, 3108c2ecf20Sopenharmony_ci * pointing to value of variable. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_ci struct tls_index tls_index; 3138c2ecf20Sopenharmony_ci dtv_t *dtv; 3148c2ecf20Sopenharmony_ci void *tls_ptr; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci bpf_probe_read_user(&tls_index, sizeof(struct tls_index), 3178c2ecf20Sopenharmony_ci (void *)loc->offset); 3188c2ecf20Sopenharmony_ci /* valid module index is always positive */ 3198c2ecf20Sopenharmony_ci if (tls_index.module > 0) { 3208c2ecf20Sopenharmony_ci /* dtv = ((struct tcbhead *)tls_base)->dtv[tls_index.module] */ 3218c2ecf20Sopenharmony_ci bpf_probe_read_user(&dtv, sizeof(dtv), 3228c2ecf20Sopenharmony_ci &((struct tcbhead *)tls_base)->dtv); 3238c2ecf20Sopenharmony_ci dtv += tls_index.module; 3248c2ecf20Sopenharmony_ci } else { 3258c2ecf20Sopenharmony_ci dtv = NULL; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci bpf_probe_read_user(&tls_ptr, sizeof(void *), dtv); 3288c2ecf20Sopenharmony_ci /* if pointer has (void *)-1 value, then TLS wasn't initialized yet */ 3298c2ecf20Sopenharmony_ci return tls_ptr && tls_ptr != (void *)-1 3308c2ecf20Sopenharmony_ci ? tls_ptr + tls_index.offset 3318c2ecf20Sopenharmony_ci : NULL; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci#ifdef SUBPROGS 3358c2ecf20Sopenharmony_ci__noinline 3368c2ecf20Sopenharmony_ci#else 3378c2ecf20Sopenharmony_ci__always_inline 3388c2ecf20Sopenharmony_ci#endif 3398c2ecf20Sopenharmony_cistatic void read_int_var(struct strobemeta_cfg *cfg, 3408c2ecf20Sopenharmony_ci size_t idx, void *tls_base, 3418c2ecf20Sopenharmony_ci struct strobe_value_generic *value, 3428c2ecf20Sopenharmony_ci struct strobemeta_payload *data) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci void *location = calc_location(&cfg->int_locs[idx], tls_base); 3458c2ecf20Sopenharmony_ci if (!location) 3468c2ecf20Sopenharmony_ci return; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci bpf_probe_read_user(value, sizeof(struct strobe_value_generic), location); 3498c2ecf20Sopenharmony_ci data->int_vals[idx] = value->val; 3508c2ecf20Sopenharmony_ci if (value->header.len) 3518c2ecf20Sopenharmony_ci data->int_vals_set_mask |= (1 << idx); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic __always_inline uint64_t read_str_var(struct strobemeta_cfg *cfg, 3558c2ecf20Sopenharmony_ci size_t idx, void *tls_base, 3568c2ecf20Sopenharmony_ci struct strobe_value_generic *value, 3578c2ecf20Sopenharmony_ci struct strobemeta_payload *data, 3588c2ecf20Sopenharmony_ci void *payload) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci void *location; 3618c2ecf20Sopenharmony_ci uint64_t len; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci data->str_lens[idx] = 0; 3648c2ecf20Sopenharmony_ci location = calc_location(&cfg->str_locs[idx], tls_base); 3658c2ecf20Sopenharmony_ci if (!location) 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci bpf_probe_read_user(value, sizeof(struct strobe_value_generic), location); 3698c2ecf20Sopenharmony_ci len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, value->ptr); 3708c2ecf20Sopenharmony_ci /* 3718c2ecf20Sopenharmony_ci * if bpf_probe_read_user_str returns error (<0), due to casting to 3728c2ecf20Sopenharmony_ci * unsinged int, it will become big number, so next check is 3738c2ecf20Sopenharmony_ci * sufficient to check for errors AND prove to BPF verifier, that 3748c2ecf20Sopenharmony_ci * bpf_probe_read_user_str won't return anything bigger than 3758c2ecf20Sopenharmony_ci * STROBE_MAX_STR_LEN 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci if (len > STROBE_MAX_STR_LEN) 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci data->str_lens[idx] = len; 3818c2ecf20Sopenharmony_ci return len; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic __always_inline void *read_map_var(struct strobemeta_cfg *cfg, 3858c2ecf20Sopenharmony_ci size_t idx, void *tls_base, 3868c2ecf20Sopenharmony_ci struct strobe_value_generic *value, 3878c2ecf20Sopenharmony_ci struct strobemeta_payload *data, 3888c2ecf20Sopenharmony_ci void *payload) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct strobe_map_descr* descr = &data->map_descrs[idx]; 3918c2ecf20Sopenharmony_ci struct strobe_map_raw map; 3928c2ecf20Sopenharmony_ci void *location; 3938c2ecf20Sopenharmony_ci uint64_t len; 3948c2ecf20Sopenharmony_ci int i; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci descr->tag_len = 0; /* presume no tag is set */ 3978c2ecf20Sopenharmony_ci descr->cnt = -1; /* presume no value is set */ 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci location = calc_location(&cfg->map_locs[idx], tls_base); 4008c2ecf20Sopenharmony_ci if (!location) 4018c2ecf20Sopenharmony_ci return payload; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci bpf_probe_read_user(value, sizeof(struct strobe_value_generic), location); 4048c2ecf20Sopenharmony_ci if (bpf_probe_read_user(&map, sizeof(struct strobe_map_raw), value->ptr)) 4058c2ecf20Sopenharmony_ci return payload; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci descr->id = map.id; 4088c2ecf20Sopenharmony_ci descr->cnt = map.cnt; 4098c2ecf20Sopenharmony_ci if (cfg->req_meta_idx == idx) { 4108c2ecf20Sopenharmony_ci data->req_id = map.id; 4118c2ecf20Sopenharmony_ci data->req_meta_valid = 1; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, map.tag); 4158c2ecf20Sopenharmony_ci if (len <= STROBE_MAX_STR_LEN) { 4168c2ecf20Sopenharmony_ci descr->tag_len = len; 4178c2ecf20Sopenharmony_ci payload += len; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci#ifdef NO_UNROLL 4218c2ecf20Sopenharmony_ci#pragma clang loop unroll(disable) 4228c2ecf20Sopenharmony_ci#else 4238c2ecf20Sopenharmony_ci#pragma unroll 4248c2ecf20Sopenharmony_ci#endif 4258c2ecf20Sopenharmony_ci for (int i = 0; i < STROBE_MAX_MAP_ENTRIES; ++i) { 4268c2ecf20Sopenharmony_ci if (i >= map.cnt) 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci descr->key_lens[i] = 0; 4308c2ecf20Sopenharmony_ci len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, 4318c2ecf20Sopenharmony_ci map.entries[i].key); 4328c2ecf20Sopenharmony_ci if (len <= STROBE_MAX_STR_LEN) { 4338c2ecf20Sopenharmony_ci descr->key_lens[i] = len; 4348c2ecf20Sopenharmony_ci payload += len; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci descr->val_lens[i] = 0; 4378c2ecf20Sopenharmony_ci len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, 4388c2ecf20Sopenharmony_ci map.entries[i].val); 4398c2ecf20Sopenharmony_ci if (len <= STROBE_MAX_STR_LEN) { 4408c2ecf20Sopenharmony_ci descr->val_lens[i] = len; 4418c2ecf20Sopenharmony_ci payload += len; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return payload; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/* 4498c2ecf20Sopenharmony_ci * read_strobe_meta returns NULL, if no metadata was read; otherwise returns 4508c2ecf20Sopenharmony_ci * pointer to *right after* payload ends 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_ci#ifdef SUBPROGS 4538c2ecf20Sopenharmony_ci__noinline 4548c2ecf20Sopenharmony_ci#else 4558c2ecf20Sopenharmony_ci__always_inline 4568c2ecf20Sopenharmony_ci#endif 4578c2ecf20Sopenharmony_cistatic void *read_strobe_meta(struct task_struct *task, 4588c2ecf20Sopenharmony_ci struct strobemeta_payload *data) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci pid_t pid = bpf_get_current_pid_tgid() >> 32; 4618c2ecf20Sopenharmony_ci struct strobe_value_generic value = {0}; 4628c2ecf20Sopenharmony_ci struct strobemeta_cfg *cfg; 4638c2ecf20Sopenharmony_ci void *tls_base, *payload; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci cfg = bpf_map_lookup_elem(&strobemeta_cfgs, &pid); 4668c2ecf20Sopenharmony_ci if (!cfg) 4678c2ecf20Sopenharmony_ci return NULL; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci data->int_vals_set_mask = 0; 4708c2ecf20Sopenharmony_ci data->req_meta_valid = 0; 4718c2ecf20Sopenharmony_ci payload = data->payload; 4728c2ecf20Sopenharmony_ci /* 4738c2ecf20Sopenharmony_ci * we don't have struct task_struct definition, it should be: 4748c2ecf20Sopenharmony_ci * tls_base = (void *)task->thread.fsbase; 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci tls_base = (void *)task; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci#ifdef NO_UNROLL 4798c2ecf20Sopenharmony_ci#pragma clang loop unroll(disable) 4808c2ecf20Sopenharmony_ci#else 4818c2ecf20Sopenharmony_ci#pragma unroll 4828c2ecf20Sopenharmony_ci#endif 4838c2ecf20Sopenharmony_ci for (int i = 0; i < STROBE_MAX_INTS; ++i) { 4848c2ecf20Sopenharmony_ci read_int_var(cfg, i, tls_base, &value, data); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci#ifdef NO_UNROLL 4878c2ecf20Sopenharmony_ci#pragma clang loop unroll(disable) 4888c2ecf20Sopenharmony_ci#else 4898c2ecf20Sopenharmony_ci#pragma unroll 4908c2ecf20Sopenharmony_ci#endif 4918c2ecf20Sopenharmony_ci for (int i = 0; i < STROBE_MAX_STRS; ++i) { 4928c2ecf20Sopenharmony_ci payload += read_str_var(cfg, i, tls_base, &value, data, payload); 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci#ifdef NO_UNROLL 4958c2ecf20Sopenharmony_ci#pragma clang loop unroll(disable) 4968c2ecf20Sopenharmony_ci#else 4978c2ecf20Sopenharmony_ci#pragma unroll 4988c2ecf20Sopenharmony_ci#endif 4998c2ecf20Sopenharmony_ci for (int i = 0; i < STROBE_MAX_MAPS; ++i) { 5008c2ecf20Sopenharmony_ci payload = read_map_var(cfg, i, tls_base, &value, data, payload); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci /* 5038c2ecf20Sopenharmony_ci * return pointer right after end of payload, so it's possible to 5048c2ecf20Sopenharmony_ci * calculate exact amount of useful data that needs to be sent 5058c2ecf20Sopenharmony_ci */ 5068c2ecf20Sopenharmony_ci return payload; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ciSEC("raw_tracepoint/kfree_skb") 5108c2ecf20Sopenharmony_ciint on_event(struct pt_regs *ctx) { 5118c2ecf20Sopenharmony_ci pid_t pid = bpf_get_current_pid_tgid() >> 32; 5128c2ecf20Sopenharmony_ci struct strobelight_bpf_sample* sample; 5138c2ecf20Sopenharmony_ci struct task_struct *task; 5148c2ecf20Sopenharmony_ci uint32_t zero = 0; 5158c2ecf20Sopenharmony_ci uint64_t ktime_ns; 5168c2ecf20Sopenharmony_ci void *sample_end; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci sample = bpf_map_lookup_elem(&sample_heap, &zero); 5198c2ecf20Sopenharmony_ci if (!sample) 5208c2ecf20Sopenharmony_ci return 0; /* this will never happen */ 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci sample->pid = pid; 5238c2ecf20Sopenharmony_ci bpf_get_current_comm(&sample->comm, TASK_COMM_LEN); 5248c2ecf20Sopenharmony_ci ktime_ns = bpf_ktime_get_ns(); 5258c2ecf20Sopenharmony_ci sample->ktime = ktime_ns; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci task = (struct task_struct *)bpf_get_current_task(); 5288c2ecf20Sopenharmony_ci sample_end = read_strobe_meta(task, &sample->metadata); 5298c2ecf20Sopenharmony_ci sample->has_meta = sample_end != NULL; 5308c2ecf20Sopenharmony_ci sample_end = sample_end ? : &sample->metadata; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if ((ktime_ns >> STACK_TABLE_EPOCH_SHIFT) & 1) { 5338c2ecf20Sopenharmony_ci sample->kernel_stack_id = bpf_get_stackid(ctx, &stacks_1, 0); 5348c2ecf20Sopenharmony_ci sample->user_stack_id = bpf_get_stackid(ctx, &stacks_1, BPF_F_USER_STACK); 5358c2ecf20Sopenharmony_ci } else { 5368c2ecf20Sopenharmony_ci sample->kernel_stack_id = bpf_get_stackid(ctx, &stacks_0, 0); 5378c2ecf20Sopenharmony_ci sample->user_stack_id = bpf_get_stackid(ctx, &stacks_0, BPF_F_USER_STACK); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci uint64_t sample_size = sample_end - (void *)sample; 5418c2ecf20Sopenharmony_ci /* should always be true */ 5428c2ecf20Sopenharmony_ci if (sample_size < sizeof(struct strobelight_bpf_sample)) 5438c2ecf20Sopenharmony_ci bpf_perf_event_output(ctx, &samples, 0, sample, 1 + sample_size); 5448c2ecf20Sopenharmony_ci return 0; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cichar _license[] SEC("license") = "GPL"; 548