1*387f9dfdSAndroid Build Coastguard Worker /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2*387f9dfdSAndroid Build Coastguard Worker /* Copyright (c) 2021, Oracle and/or its affiliates. */
3*387f9dfdSAndroid Build Coastguard Worker
4*387f9dfdSAndroid Build Coastguard Worker #include <ctype.h>
5*387f9dfdSAndroid Build Coastguard Worker #include <errno.h>
6*387f9dfdSAndroid Build Coastguard Worker #include <getopt.h>
7*387f9dfdSAndroid Build Coastguard Worker #include <signal.h>
8*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
9*387f9dfdSAndroid Build Coastguard Worker #include <stdlib.h>
10*387f9dfdSAndroid Build Coastguard Worker #include <string.h>
11*387f9dfdSAndroid Build Coastguard Worker
12*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf.h>
13*387f9dfdSAndroid Build Coastguard Worker #include <bpf/libbpf.h>
14*387f9dfdSAndroid Build Coastguard Worker #include <bpf/btf.h>
15*387f9dfdSAndroid Build Coastguard Worker
16*387f9dfdSAndroid Build Coastguard Worker #include "ksnoop.h"
17*387f9dfdSAndroid Build Coastguard Worker #include "ksnoop.skel.h"
18*387f9dfdSAndroid Build Coastguard Worker
19*387f9dfdSAndroid Build Coastguard Worker #ifndef KSNOOP_VERSION
20*387f9dfdSAndroid Build Coastguard Worker #define KSNOOP_VERSION "0.1"
21*387f9dfdSAndroid Build Coastguard Worker #endif
22*387f9dfdSAndroid Build Coastguard Worker
23*387f9dfdSAndroid Build Coastguard Worker static volatile sig_atomic_t exiting = 0;
24*387f9dfdSAndroid Build Coastguard Worker
25*387f9dfdSAndroid Build Coastguard Worker static struct btf *vmlinux_btf;
26*387f9dfdSAndroid Build Coastguard Worker static const char *bin_name;
27*387f9dfdSAndroid Build Coastguard Worker static int pages = PAGES_DEFAULT;
28*387f9dfdSAndroid Build Coastguard Worker
29*387f9dfdSAndroid Build Coastguard Worker enum log_level {
30*387f9dfdSAndroid Build Coastguard Worker DEBUG,
31*387f9dfdSAndroid Build Coastguard Worker WARN,
32*387f9dfdSAndroid Build Coastguard Worker ERROR,
33*387f9dfdSAndroid Build Coastguard Worker };
34*387f9dfdSAndroid Build Coastguard Worker
35*387f9dfdSAndroid Build Coastguard Worker static enum log_level log_level = WARN;
36*387f9dfdSAndroid Build Coastguard Worker static bool verbose = false;
37*387f9dfdSAndroid Build Coastguard Worker
38*387f9dfdSAndroid Build Coastguard Worker static __u32 filter_pid;
39*387f9dfdSAndroid Build Coastguard Worker static bool stack_mode;
40*387f9dfdSAndroid Build Coastguard Worker
41*387f9dfdSAndroid Build Coastguard Worker
__p(enum log_level level,char * level_str,char * fmt,...)42*387f9dfdSAndroid Build Coastguard Worker static void __p(enum log_level level, char *level_str, char *fmt, ...)
43*387f9dfdSAndroid Build Coastguard Worker {
44*387f9dfdSAndroid Build Coastguard Worker va_list ap;
45*387f9dfdSAndroid Build Coastguard Worker
46*387f9dfdSAndroid Build Coastguard Worker if (level < log_level)
47*387f9dfdSAndroid Build Coastguard Worker return;
48*387f9dfdSAndroid Build Coastguard Worker va_start(ap, fmt);
49*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "%s: ", level_str);
50*387f9dfdSAndroid Build Coastguard Worker vfprintf(stderr, fmt, ap);
51*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "\n");
52*387f9dfdSAndroid Build Coastguard Worker va_end(ap);
53*387f9dfdSAndroid Build Coastguard Worker fflush(stderr);
54*387f9dfdSAndroid Build Coastguard Worker }
55*387f9dfdSAndroid Build Coastguard Worker
56*387f9dfdSAndroid Build Coastguard Worker #define p_err(fmt, ...) __p(ERROR, "Error", fmt, ##__VA_ARGS__)
57*387f9dfdSAndroid Build Coastguard Worker #define p_warn(fmt, ...) __p(WARNING, "Warn", fmt, ##__VA_ARGS__)
58*387f9dfdSAndroid Build Coastguard Worker #define p_debug(fmt, ...) __p(DEBUG, "Debug", fmt, ##__VA_ARGS__)
59*387f9dfdSAndroid Build Coastguard Worker
do_version(int argc,char ** argv)60*387f9dfdSAndroid Build Coastguard Worker static int do_version(int argc, char **argv)
61*387f9dfdSAndroid Build Coastguard Worker {
62*387f9dfdSAndroid Build Coastguard Worker printf("%s v%s\n", bin_name, KSNOOP_VERSION);
63*387f9dfdSAndroid Build Coastguard Worker return 0;
64*387f9dfdSAndroid Build Coastguard Worker }
65*387f9dfdSAndroid Build Coastguard Worker
cmd_help(int argc,char ** argv)66*387f9dfdSAndroid Build Coastguard Worker static int cmd_help(int argc, char **argv)
67*387f9dfdSAndroid Build Coastguard Worker {
68*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr,
69*387f9dfdSAndroid Build Coastguard Worker "Usage: %s [OPTIONS] [COMMAND | help] FUNC\n"
70*387f9dfdSAndroid Build Coastguard Worker " COMMAND := { trace | info }\n"
71*387f9dfdSAndroid Build Coastguard Worker " FUNC := { name | name(ARG[,ARG]*) }\n"
72*387f9dfdSAndroid Build Coastguard Worker " ARG := { arg | arg [PRED] | arg->member [PRED] }\n"
73*387f9dfdSAndroid Build Coastguard Worker " PRED := { == | != | > | >= | < | <= value }\n"
74*387f9dfdSAndroid Build Coastguard Worker " OPTIONS := { {-d|--debug} | {-v|--verbose} | {-V|--version} |\n"
75*387f9dfdSAndroid Build Coastguard Worker " {-p|--pid filter_pid}|\n"
76*387f9dfdSAndroid Build Coastguard Worker " {-P|--pages nr_pages} }\n"
77*387f9dfdSAndroid Build Coastguard Worker " {-s|--stack}\n",
78*387f9dfdSAndroid Build Coastguard Worker bin_name);
79*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr,
80*387f9dfdSAndroid Build Coastguard Worker "Examples:\n"
81*387f9dfdSAndroid Build Coastguard Worker " %s info ip_send_skb\n"
82*387f9dfdSAndroid Build Coastguard Worker " %s trace ip_send_skb\n"
83*387f9dfdSAndroid Build Coastguard Worker " %s trace \"ip_send_skb(skb, return)\"\n"
84*387f9dfdSAndroid Build Coastguard Worker " %s trace \"ip_send_skb(skb->sk, return)\"\n"
85*387f9dfdSAndroid Build Coastguard Worker " %s trace \"ip_send_skb(skb->len > 128, skb)\"\n"
86*387f9dfdSAndroid Build Coastguard Worker " %s trace -s udp_sendmsg ip_send_skb\n",
87*387f9dfdSAndroid Build Coastguard Worker bin_name, bin_name, bin_name, bin_name, bin_name, bin_name);
88*387f9dfdSAndroid Build Coastguard Worker return 0;
89*387f9dfdSAndroid Build Coastguard Worker }
90*387f9dfdSAndroid Build Coastguard Worker
usage(void)91*387f9dfdSAndroid Build Coastguard Worker static void usage(void)
92*387f9dfdSAndroid Build Coastguard Worker {
93*387f9dfdSAndroid Build Coastguard Worker cmd_help(0, NULL);
94*387f9dfdSAndroid Build Coastguard Worker exit(1);
95*387f9dfdSAndroid Build Coastguard Worker }
96*387f9dfdSAndroid Build Coastguard Worker
type_to_value(struct btf * btf,char * name,__u32 type_id,struct value * val)97*387f9dfdSAndroid Build Coastguard Worker static void type_to_value(struct btf *btf, char *name, __u32 type_id,
98*387f9dfdSAndroid Build Coastguard Worker struct value *val)
99*387f9dfdSAndroid Build Coastguard Worker {
100*387f9dfdSAndroid Build Coastguard Worker const struct btf_type *type;
101*387f9dfdSAndroid Build Coastguard Worker __s32 id = type_id;
102*387f9dfdSAndroid Build Coastguard Worker
103*387f9dfdSAndroid Build Coastguard Worker if (strlen(val->name) == 0) {
104*387f9dfdSAndroid Build Coastguard Worker if (name)
105*387f9dfdSAndroid Build Coastguard Worker strncpy(val->name, name,
106*387f9dfdSAndroid Build Coastguard Worker sizeof(val->name) - 1);
107*387f9dfdSAndroid Build Coastguard Worker else
108*387f9dfdSAndroid Build Coastguard Worker val->name[0] = '\0';
109*387f9dfdSAndroid Build Coastguard Worker }
110*387f9dfdSAndroid Build Coastguard Worker do {
111*387f9dfdSAndroid Build Coastguard Worker type = btf__type_by_id(btf, id);
112*387f9dfdSAndroid Build Coastguard Worker
113*387f9dfdSAndroid Build Coastguard Worker switch (BTF_INFO_KIND(type->info)) {
114*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_CONST:
115*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_VOLATILE:
116*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_RESTRICT:
117*387f9dfdSAndroid Build Coastguard Worker id = type->type;
118*387f9dfdSAndroid Build Coastguard Worker break;
119*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_PTR:
120*387f9dfdSAndroid Build Coastguard Worker val->flags |= KSNOOP_F_PTR;
121*387f9dfdSAndroid Build Coastguard Worker id = type->type;
122*387f9dfdSAndroid Build Coastguard Worker break;
123*387f9dfdSAndroid Build Coastguard Worker default:
124*387f9dfdSAndroid Build Coastguard Worker val->type_id = id;
125*387f9dfdSAndroid Build Coastguard Worker goto done;
126*387f9dfdSAndroid Build Coastguard Worker }
127*387f9dfdSAndroid Build Coastguard Worker } while (id >= 0);
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Worker val->type_id = KSNOOP_ID_UNKNOWN;
130*387f9dfdSAndroid Build Coastguard Worker return;
131*387f9dfdSAndroid Build Coastguard Worker done:
132*387f9dfdSAndroid Build Coastguard Worker val->size = btf__resolve_size(btf, val->type_id);
133*387f9dfdSAndroid Build Coastguard Worker }
134*387f9dfdSAndroid Build Coastguard Worker
member_to_value(struct btf * btf,const char * name,__u32 type_id,struct value * val,int lvl)135*387f9dfdSAndroid Build Coastguard Worker static int member_to_value(struct btf *btf, const char *name, __u32 type_id,
136*387f9dfdSAndroid Build Coastguard Worker struct value *val, int lvl)
137*387f9dfdSAndroid Build Coastguard Worker {
138*387f9dfdSAndroid Build Coastguard Worker const struct btf_member *member;
139*387f9dfdSAndroid Build Coastguard Worker const struct btf_type *type;
140*387f9dfdSAndroid Build Coastguard Worker const char *pname;
141*387f9dfdSAndroid Build Coastguard Worker __s32 id = type_id;
142*387f9dfdSAndroid Build Coastguard Worker int i, nmembers;
143*387f9dfdSAndroid Build Coastguard Worker __u8 kind;
144*387f9dfdSAndroid Build Coastguard Worker
145*387f9dfdSAndroid Build Coastguard Worker /* type_to_value has already stripped qualifiers, so
146*387f9dfdSAndroid Build Coastguard Worker * we either have a base type, a struct, union, etc.
147*387f9dfdSAndroid Build Coastguard Worker * Only struct/unions have named members so anything
148*387f9dfdSAndroid Build Coastguard Worker * else is invalid.
149*387f9dfdSAndroid Build Coastguard Worker */
150*387f9dfdSAndroid Build Coastguard Worker p_debug("Looking for member '%s' in type id %d", name, type_id);
151*387f9dfdSAndroid Build Coastguard Worker type = btf__type_by_id(btf, id);
152*387f9dfdSAndroid Build Coastguard Worker pname = btf__str_by_offset(btf, type->name_off);
153*387f9dfdSAndroid Build Coastguard Worker if (strlen(pname) == 0)
154*387f9dfdSAndroid Build Coastguard Worker pname = "<anon>";
155*387f9dfdSAndroid Build Coastguard Worker
156*387f9dfdSAndroid Build Coastguard Worker kind = BTF_INFO_KIND(type->info);
157*387f9dfdSAndroid Build Coastguard Worker switch (kind) {
158*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_STRUCT:
159*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_UNION:
160*387f9dfdSAndroid Build Coastguard Worker nmembers = BTF_INFO_VLEN(type->info);
161*387f9dfdSAndroid Build Coastguard Worker p_debug("Checking %d members...", nmembers);
162*387f9dfdSAndroid Build Coastguard Worker for (member = (struct btf_member *)(type + 1), i = 0;
163*387f9dfdSAndroid Build Coastguard Worker i < nmembers;
164*387f9dfdSAndroid Build Coastguard Worker member++, i++) {
165*387f9dfdSAndroid Build Coastguard Worker const char *mname;
166*387f9dfdSAndroid Build Coastguard Worker __u16 offset;
167*387f9dfdSAndroid Build Coastguard Worker
168*387f9dfdSAndroid Build Coastguard Worker type = btf__type_by_id(btf, member->type);
169*387f9dfdSAndroid Build Coastguard Worker mname = btf__str_by_offset(btf, member->name_off);
170*387f9dfdSAndroid Build Coastguard Worker offset = member->offset / 8;
171*387f9dfdSAndroid Build Coastguard Worker
172*387f9dfdSAndroid Build Coastguard Worker p_debug("Checking member '%s' type %d offset %d",
173*387f9dfdSAndroid Build Coastguard Worker mname, member->type, offset);
174*387f9dfdSAndroid Build Coastguard Worker
175*387f9dfdSAndroid Build Coastguard Worker /* anonymous struct member? */
176*387f9dfdSAndroid Build Coastguard Worker kind = BTF_INFO_KIND(type->info);
177*387f9dfdSAndroid Build Coastguard Worker if (strlen(mname) == 0 &&
178*387f9dfdSAndroid Build Coastguard Worker (kind == BTF_KIND_STRUCT ||
179*387f9dfdSAndroid Build Coastguard Worker kind == BTF_KIND_UNION)) {
180*387f9dfdSAndroid Build Coastguard Worker p_debug("Checking anon struct/union %d",
181*387f9dfdSAndroid Build Coastguard Worker member->type);
182*387f9dfdSAndroid Build Coastguard Worker val->offset += offset;
183*387f9dfdSAndroid Build Coastguard Worker if (!member_to_value(btf, name, member->type,
184*387f9dfdSAndroid Build Coastguard Worker val, lvl + 1))
185*387f9dfdSAndroid Build Coastguard Worker return 0;
186*387f9dfdSAndroid Build Coastguard Worker val->offset -= offset;
187*387f9dfdSAndroid Build Coastguard Worker continue;
188*387f9dfdSAndroid Build Coastguard Worker }
189*387f9dfdSAndroid Build Coastguard Worker
190*387f9dfdSAndroid Build Coastguard Worker if (strcmp(mname, name) == 0) {
191*387f9dfdSAndroid Build Coastguard Worker val->offset += offset;
192*387f9dfdSAndroid Build Coastguard Worker val->flags |= KSNOOP_F_MEMBER;
193*387f9dfdSAndroid Build Coastguard Worker type_to_value(btf, NULL, member->type, val);
194*387f9dfdSAndroid Build Coastguard Worker p_debug("Member '%s', offset %d, flags %x size %d",
195*387f9dfdSAndroid Build Coastguard Worker mname, val->offset, val->flags,
196*387f9dfdSAndroid Build Coastguard Worker val->size);
197*387f9dfdSAndroid Build Coastguard Worker return 0;
198*387f9dfdSAndroid Build Coastguard Worker }
199*387f9dfdSAndroid Build Coastguard Worker }
200*387f9dfdSAndroid Build Coastguard Worker if (lvl > 0)
201*387f9dfdSAndroid Build Coastguard Worker break;
202*387f9dfdSAndroid Build Coastguard Worker p_err("No member '%s' found in %s [%d], offset %d", name, pname,
203*387f9dfdSAndroid Build Coastguard Worker id, val->offset);
204*387f9dfdSAndroid Build Coastguard Worker break;
205*387f9dfdSAndroid Build Coastguard Worker default:
206*387f9dfdSAndroid Build Coastguard Worker p_err("'%s' is not a struct/union", pname);
207*387f9dfdSAndroid Build Coastguard Worker break;
208*387f9dfdSAndroid Build Coastguard Worker }
209*387f9dfdSAndroid Build Coastguard Worker return -ENOENT;
210*387f9dfdSAndroid Build Coastguard Worker }
211*387f9dfdSAndroid Build Coastguard Worker
get_func_btf(struct btf * btf,struct func * func)212*387f9dfdSAndroid Build Coastguard Worker static int get_func_btf(struct btf *btf, struct func *func)
213*387f9dfdSAndroid Build Coastguard Worker {
214*387f9dfdSAndroid Build Coastguard Worker const struct btf_param *param;
215*387f9dfdSAndroid Build Coastguard Worker const struct btf_type *type;
216*387f9dfdSAndroid Build Coastguard Worker __u8 i;
217*387f9dfdSAndroid Build Coastguard Worker
218*387f9dfdSAndroid Build Coastguard Worker func->id = btf__find_by_name_kind(btf, func->name, BTF_KIND_FUNC);
219*387f9dfdSAndroid Build Coastguard Worker if (func->id <= 0) {
220*387f9dfdSAndroid Build Coastguard Worker p_err("Cannot find function '%s' in BTF: %s",
221*387f9dfdSAndroid Build Coastguard Worker func->name, strerror(-func->id));
222*387f9dfdSAndroid Build Coastguard Worker return -ENOENT;
223*387f9dfdSAndroid Build Coastguard Worker }
224*387f9dfdSAndroid Build Coastguard Worker type = btf__type_by_id(btf, func->id);
225*387f9dfdSAndroid Build Coastguard Worker if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC) {
226*387f9dfdSAndroid Build Coastguard Worker p_err("Error looking up function type via id '%d'", func->id);
227*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
228*387f9dfdSAndroid Build Coastguard Worker }
229*387f9dfdSAndroid Build Coastguard Worker type = btf__type_by_id(btf, type->type);
230*387f9dfdSAndroid Build Coastguard Worker if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC_PROTO) {
231*387f9dfdSAndroid Build Coastguard Worker p_err("Error looking up function proto type via id '%d'",
232*387f9dfdSAndroid Build Coastguard Worker func->id);
233*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
234*387f9dfdSAndroid Build Coastguard Worker }
235*387f9dfdSAndroid Build Coastguard Worker for (param = (struct btf_param *)(type + 1), i = 0;
236*387f9dfdSAndroid Build Coastguard Worker i < BTF_INFO_VLEN(type->info) && i < MAX_ARGS;
237*387f9dfdSAndroid Build Coastguard Worker param++, i++) {
238*387f9dfdSAndroid Build Coastguard Worker type_to_value(btf,
239*387f9dfdSAndroid Build Coastguard Worker (char *)btf__str_by_offset(btf, param->name_off),
240*387f9dfdSAndroid Build Coastguard Worker param->type, &func->args[i]);
241*387f9dfdSAndroid Build Coastguard Worker p_debug("arg #%d: <name '%s', type id '%u'>",
242*387f9dfdSAndroid Build Coastguard Worker i + 1, func->args[i].name, func->args[i].type_id);
243*387f9dfdSAndroid Build Coastguard Worker }
244*387f9dfdSAndroid Build Coastguard Worker
245*387f9dfdSAndroid Build Coastguard Worker /* real number of args, even if it is > number we recorded. */
246*387f9dfdSAndroid Build Coastguard Worker func->nr_args = BTF_INFO_VLEN(type->info);
247*387f9dfdSAndroid Build Coastguard Worker
248*387f9dfdSAndroid Build Coastguard Worker type_to_value(btf, KSNOOP_RETURN_NAME, type->type,
249*387f9dfdSAndroid Build Coastguard Worker &func->args[KSNOOP_RETURN]);
250*387f9dfdSAndroid Build Coastguard Worker p_debug("return value: type id '%u'>",
251*387f9dfdSAndroid Build Coastguard Worker func->args[KSNOOP_RETURN].type_id);
252*387f9dfdSAndroid Build Coastguard Worker return 0;
253*387f9dfdSAndroid Build Coastguard Worker }
254*387f9dfdSAndroid Build Coastguard Worker
predicate_to_value(char * predicate,struct value * val)255*387f9dfdSAndroid Build Coastguard Worker static int predicate_to_value(char *predicate, struct value *val)
256*387f9dfdSAndroid Build Coastguard Worker {
257*387f9dfdSAndroid Build Coastguard Worker char pred[MAX_STR];
258*387f9dfdSAndroid Build Coastguard Worker long v;
259*387f9dfdSAndroid Build Coastguard Worker
260*387f9dfdSAndroid Build Coastguard Worker if (!predicate)
261*387f9dfdSAndroid Build Coastguard Worker return 0;
262*387f9dfdSAndroid Build Coastguard Worker
263*387f9dfdSAndroid Build Coastguard Worker p_debug("checking predicate '%s' for '%s'", predicate, val->name);
264*387f9dfdSAndroid Build Coastguard Worker
265*387f9dfdSAndroid Build Coastguard Worker if (sscanf(predicate, "%[!=><]%li", pred, &v) != 2) {
266*387f9dfdSAndroid Build Coastguard Worker p_err("Invalid specification; expected predicate, not '%s'",
267*387f9dfdSAndroid Build Coastguard Worker predicate);
268*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
269*387f9dfdSAndroid Build Coastguard Worker }
270*387f9dfdSAndroid Build Coastguard Worker if (!(val->flags & KSNOOP_F_PTR) &&
271*387f9dfdSAndroid Build Coastguard Worker (val->size == 0 || val->size > sizeof(__u64))) {
272*387f9dfdSAndroid Build Coastguard Worker p_err("'%s' (size %d) does not support predicate comparison",
273*387f9dfdSAndroid Build Coastguard Worker val->name, val->size);
274*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
275*387f9dfdSAndroid Build Coastguard Worker }
276*387f9dfdSAndroid Build Coastguard Worker val->predicate_value = (__u64)v;
277*387f9dfdSAndroid Build Coastguard Worker
278*387f9dfdSAndroid Build Coastguard Worker if (strcmp(pred, "==") == 0) {
279*387f9dfdSAndroid Build Coastguard Worker val->flags |= KSNOOP_F_PREDICATE_EQ;
280*387f9dfdSAndroid Build Coastguard Worker goto out;
281*387f9dfdSAndroid Build Coastguard Worker } else if (strcmp(pred, "!=") == 0) {
282*387f9dfdSAndroid Build Coastguard Worker val->flags |= KSNOOP_F_PREDICATE_NOTEQ;
283*387f9dfdSAndroid Build Coastguard Worker goto out;
284*387f9dfdSAndroid Build Coastguard Worker }
285*387f9dfdSAndroid Build Coastguard Worker if (pred[0] == '>')
286*387f9dfdSAndroid Build Coastguard Worker val->flags |= KSNOOP_F_PREDICATE_GT;
287*387f9dfdSAndroid Build Coastguard Worker else if (pred[0] == '<')
288*387f9dfdSAndroid Build Coastguard Worker val->flags |= KSNOOP_F_PREDICATE_LT;
289*387f9dfdSAndroid Build Coastguard Worker
290*387f9dfdSAndroid Build Coastguard Worker if (strlen(pred) == 1)
291*387f9dfdSAndroid Build Coastguard Worker goto out;
292*387f9dfdSAndroid Build Coastguard Worker
293*387f9dfdSAndroid Build Coastguard Worker if (pred[1] != '=') {
294*387f9dfdSAndroid Build Coastguard Worker p_err("Invalid predicate specification '%s'", predicate);
295*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
296*387f9dfdSAndroid Build Coastguard Worker }
297*387f9dfdSAndroid Build Coastguard Worker val->flags |= KSNOOP_F_PREDICATE_EQ;
298*387f9dfdSAndroid Build Coastguard Worker
299*387f9dfdSAndroid Build Coastguard Worker out:
300*387f9dfdSAndroid Build Coastguard Worker p_debug("predicate '%s', flags 0x%x value %x",
301*387f9dfdSAndroid Build Coastguard Worker pred, val->flags, val->predicate_value);
302*387f9dfdSAndroid Build Coastguard Worker
303*387f9dfdSAndroid Build Coastguard Worker return 0;
304*387f9dfdSAndroid Build Coastguard Worker }
305*387f9dfdSAndroid Build Coastguard Worker
trace_to_value(struct btf * btf,struct func * func,char * argname,char * membername,char * predicate,struct value * val)306*387f9dfdSAndroid Build Coastguard Worker static int trace_to_value(struct btf *btf, struct func *func, char *argname,
307*387f9dfdSAndroid Build Coastguard Worker char *membername, char *predicate, struct value *val)
308*387f9dfdSAndroid Build Coastguard Worker {
309*387f9dfdSAndroid Build Coastguard Worker __u8 i;
310*387f9dfdSAndroid Build Coastguard Worker
311*387f9dfdSAndroid Build Coastguard Worker if (strlen(membername) > 0)
312*387f9dfdSAndroid Build Coastguard Worker snprintf(val->name, sizeof(val->name), "%s->%s",
313*387f9dfdSAndroid Build Coastguard Worker argname, membername);
314*387f9dfdSAndroid Build Coastguard Worker else
315*387f9dfdSAndroid Build Coastguard Worker strncpy(val->name, argname, sizeof(val->name));
316*387f9dfdSAndroid Build Coastguard Worker
317*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < MAX_TRACES; i++) {
318*387f9dfdSAndroid Build Coastguard Worker if (strcmp(argname, func->args[i].name) != 0)
319*387f9dfdSAndroid Build Coastguard Worker continue;
320*387f9dfdSAndroid Build Coastguard Worker p_debug("setting base arg for val %s to %d", val->name, i);
321*387f9dfdSAndroid Build Coastguard Worker val->base_arg = i;
322*387f9dfdSAndroid Build Coastguard Worker
323*387f9dfdSAndroid Build Coastguard Worker if (strlen(membername) > 0) {
324*387f9dfdSAndroid Build Coastguard Worker if (member_to_value(btf, membername,
325*387f9dfdSAndroid Build Coastguard Worker func->args[i].type_id, val, 0))
326*387f9dfdSAndroid Build Coastguard Worker return -ENOENT;
327*387f9dfdSAndroid Build Coastguard Worker } else {
328*387f9dfdSAndroid Build Coastguard Worker val->type_id = func->args[i].type_id;
329*387f9dfdSAndroid Build Coastguard Worker val->flags |= func->args[i].flags;
330*387f9dfdSAndroid Build Coastguard Worker val->size = func->args[i].size;
331*387f9dfdSAndroid Build Coastguard Worker }
332*387f9dfdSAndroid Build Coastguard Worker return predicate_to_value(predicate, val);
333*387f9dfdSAndroid Build Coastguard Worker }
334*387f9dfdSAndroid Build Coastguard Worker p_err("Could not find '%s' in arguments/return value for '%s'",
335*387f9dfdSAndroid Build Coastguard Worker argname, func->name);
336*387f9dfdSAndroid Build Coastguard Worker return -ENOENT;
337*387f9dfdSAndroid Build Coastguard Worker }
338*387f9dfdSAndroid Build Coastguard Worker
get_btf(const char * name)339*387f9dfdSAndroid Build Coastguard Worker static struct btf *get_btf(const char *name)
340*387f9dfdSAndroid Build Coastguard Worker {
341*387f9dfdSAndroid Build Coastguard Worker struct btf *mod_btf;
342*387f9dfdSAndroid Build Coastguard Worker int err;
343*387f9dfdSAndroid Build Coastguard Worker
344*387f9dfdSAndroid Build Coastguard Worker p_debug("getting BTF for %s",
345*387f9dfdSAndroid Build Coastguard Worker name && strlen(name) > 0 ? name : "vmlinux");
346*387f9dfdSAndroid Build Coastguard Worker
347*387f9dfdSAndroid Build Coastguard Worker if (!vmlinux_btf) {
348*387f9dfdSAndroid Build Coastguard Worker vmlinux_btf = btf__load_vmlinux_btf();
349*387f9dfdSAndroid Build Coastguard Worker if (!vmlinux_btf) {
350*387f9dfdSAndroid Build Coastguard Worker err = -errno;
351*387f9dfdSAndroid Build Coastguard Worker p_err("No BTF, cannot determine type info: %s", strerror(-err));
352*387f9dfdSAndroid Build Coastguard Worker return NULL;
353*387f9dfdSAndroid Build Coastguard Worker }
354*387f9dfdSAndroid Build Coastguard Worker }
355*387f9dfdSAndroid Build Coastguard Worker if (!name || strlen(name) == 0)
356*387f9dfdSAndroid Build Coastguard Worker return vmlinux_btf;
357*387f9dfdSAndroid Build Coastguard Worker
358*387f9dfdSAndroid Build Coastguard Worker mod_btf = btf__load_module_btf(name, vmlinux_btf);
359*387f9dfdSAndroid Build Coastguard Worker if (!mod_btf) {
360*387f9dfdSAndroid Build Coastguard Worker err = -errno;
361*387f9dfdSAndroid Build Coastguard Worker p_err("No BTF for module '%s': %s", name, strerror(-err));
362*387f9dfdSAndroid Build Coastguard Worker return NULL;
363*387f9dfdSAndroid Build Coastguard Worker }
364*387f9dfdSAndroid Build Coastguard Worker return mod_btf;
365*387f9dfdSAndroid Build Coastguard Worker }
366*387f9dfdSAndroid Build Coastguard Worker
copy_without_spaces(char * target,char * src)367*387f9dfdSAndroid Build Coastguard Worker static void copy_without_spaces(char *target, char *src)
368*387f9dfdSAndroid Build Coastguard Worker {
369*387f9dfdSAndroid Build Coastguard Worker for (; *src != '\0'; src++)
370*387f9dfdSAndroid Build Coastguard Worker if (!isspace(*src))
371*387f9dfdSAndroid Build Coastguard Worker *(target++) = *src;
372*387f9dfdSAndroid Build Coastguard Worker *target = '\0';
373*387f9dfdSAndroid Build Coastguard Worker }
374*387f9dfdSAndroid Build Coastguard Worker
type_id_to_str(struct btf * btf,__s32 type_id,char * str)375*387f9dfdSAndroid Build Coastguard Worker static char *type_id_to_str(struct btf *btf, __s32 type_id, char *str)
376*387f9dfdSAndroid Build Coastguard Worker {
377*387f9dfdSAndroid Build Coastguard Worker const struct btf_type *type;
378*387f9dfdSAndroid Build Coastguard Worker const char *name = "";
379*387f9dfdSAndroid Build Coastguard Worker char *prefix = "";
380*387f9dfdSAndroid Build Coastguard Worker char *suffix = " ";
381*387f9dfdSAndroid Build Coastguard Worker char *ptr = "";
382*387f9dfdSAndroid Build Coastguard Worker
383*387f9dfdSAndroid Build Coastguard Worker str[0] = '\0';
384*387f9dfdSAndroid Build Coastguard Worker
385*387f9dfdSAndroid Build Coastguard Worker switch (type_id) {
386*387f9dfdSAndroid Build Coastguard Worker case 0:
387*387f9dfdSAndroid Build Coastguard Worker name = "void";
388*387f9dfdSAndroid Build Coastguard Worker break;
389*387f9dfdSAndroid Build Coastguard Worker case KSNOOP_ID_UNKNOWN:
390*387f9dfdSAndroid Build Coastguard Worker name = "?";
391*387f9dfdSAndroid Build Coastguard Worker break;
392*387f9dfdSAndroid Build Coastguard Worker default:
393*387f9dfdSAndroid Build Coastguard Worker do {
394*387f9dfdSAndroid Build Coastguard Worker type = btf__type_by_id(btf, type_id);
395*387f9dfdSAndroid Build Coastguard Worker if (!type) {
396*387f9dfdSAndroid Build Coastguard Worker name = "?";
397*387f9dfdSAndroid Build Coastguard Worker break;
398*387f9dfdSAndroid Build Coastguard Worker }
399*387f9dfdSAndroid Build Coastguard Worker
400*387f9dfdSAndroid Build Coastguard Worker switch (BTF_INFO_KIND(type->info)) {
401*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_CONST:
402*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_VOLATILE:
403*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_RESTRICT:
404*387f9dfdSAndroid Build Coastguard Worker type_id = type->type;
405*387f9dfdSAndroid Build Coastguard Worker break;
406*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_PTR:
407*387f9dfdSAndroid Build Coastguard Worker ptr = "* ";
408*387f9dfdSAndroid Build Coastguard Worker type_id = type->type;
409*387f9dfdSAndroid Build Coastguard Worker break;
410*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_ARRAY:
411*387f9dfdSAndroid Build Coastguard Worker suffix = "[]";
412*387f9dfdSAndroid Build Coastguard Worker type_id = type->type;
413*387f9dfdSAndroid Build Coastguard Worker break;
414*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_STRUCT:
415*387f9dfdSAndroid Build Coastguard Worker prefix = "struct ";
416*387f9dfdSAndroid Build Coastguard Worker name = btf__str_by_offset(btf, type->name_off);
417*387f9dfdSAndroid Build Coastguard Worker break;
418*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_UNION:
419*387f9dfdSAndroid Build Coastguard Worker prefix = "union ";
420*387f9dfdSAndroid Build Coastguard Worker name = btf__str_by_offset(btf, type->name_off);
421*387f9dfdSAndroid Build Coastguard Worker break;
422*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_ENUM:
423*387f9dfdSAndroid Build Coastguard Worker prefix = "enum ";
424*387f9dfdSAndroid Build Coastguard Worker name = btf__str_by_offset(btf, type->name_off);
425*387f9dfdSAndroid Build Coastguard Worker break;
426*387f9dfdSAndroid Build Coastguard Worker case BTF_KIND_TYPEDEF:
427*387f9dfdSAndroid Build Coastguard Worker name = btf__str_by_offset(btf, type->name_off);
428*387f9dfdSAndroid Build Coastguard Worker break;
429*387f9dfdSAndroid Build Coastguard Worker default:
430*387f9dfdSAndroid Build Coastguard Worker name = btf__str_by_offset(btf, type->name_off);
431*387f9dfdSAndroid Build Coastguard Worker break;
432*387f9dfdSAndroid Build Coastguard Worker }
433*387f9dfdSAndroid Build Coastguard Worker } while (type_id >= 0 && strlen(name) == 0);
434*387f9dfdSAndroid Build Coastguard Worker break;
435*387f9dfdSAndroid Build Coastguard Worker }
436*387f9dfdSAndroid Build Coastguard Worker snprintf(str, MAX_STR, "%s%s%s%s", prefix, name, suffix, ptr);
437*387f9dfdSAndroid Build Coastguard Worker
438*387f9dfdSAndroid Build Coastguard Worker return str;
439*387f9dfdSAndroid Build Coastguard Worker }
440*387f9dfdSAndroid Build Coastguard Worker
value_to_str(struct btf * btf,struct value * val,char * str)441*387f9dfdSAndroid Build Coastguard Worker static char *value_to_str(struct btf *btf, struct value *val, char *str)
442*387f9dfdSAndroid Build Coastguard Worker {
443*387f9dfdSAndroid Build Coastguard Worker
444*387f9dfdSAndroid Build Coastguard Worker str = type_id_to_str(btf, val->type_id, str);
445*387f9dfdSAndroid Build Coastguard Worker if (val->flags & KSNOOP_F_PTR)
446*387f9dfdSAndroid Build Coastguard Worker strncat(str, "*", MAX_STR);
447*387f9dfdSAndroid Build Coastguard Worker if (strlen(val->name) > 0 &&
448*387f9dfdSAndroid Build Coastguard Worker strcmp(val->name, KSNOOP_RETURN_NAME) != 0)
449*387f9dfdSAndroid Build Coastguard Worker strncat(str, val->name, MAX_STR);
450*387f9dfdSAndroid Build Coastguard Worker
451*387f9dfdSAndroid Build Coastguard Worker return str;
452*387f9dfdSAndroid Build Coastguard Worker }
453*387f9dfdSAndroid Build Coastguard Worker
454*387f9dfdSAndroid Build Coastguard Worker /* based heavily on bpf_object__read_kallsyms_file() in libbpf.c */
get_func_ip_mod(struct func * func)455*387f9dfdSAndroid Build Coastguard Worker static int get_func_ip_mod(struct func *func)
456*387f9dfdSAndroid Build Coastguard Worker {
457*387f9dfdSAndroid Build Coastguard Worker char sym_type, sym_name[MAX_STR], mod_info[MAX_STR];
458*387f9dfdSAndroid Build Coastguard Worker unsigned long long sym_addr;
459*387f9dfdSAndroid Build Coastguard Worker int ret, err = 0;
460*387f9dfdSAndroid Build Coastguard Worker FILE *f;
461*387f9dfdSAndroid Build Coastguard Worker
462*387f9dfdSAndroid Build Coastguard Worker f = fopen("/proc/kallsyms", "r");
463*387f9dfdSAndroid Build Coastguard Worker if (!f) {
464*387f9dfdSAndroid Build Coastguard Worker err = errno;
465*387f9dfdSAndroid Build Coastguard Worker p_err("failed to open /proc/kallsyms: %s", strerror(err));
466*387f9dfdSAndroid Build Coastguard Worker return err;
467*387f9dfdSAndroid Build Coastguard Worker }
468*387f9dfdSAndroid Build Coastguard Worker
469*387f9dfdSAndroid Build Coastguard Worker while (true) {
470*387f9dfdSAndroid Build Coastguard Worker ret = fscanf(f, "%llx %c %128s%[^\n]\n",
471*387f9dfdSAndroid Build Coastguard Worker &sym_addr, &sym_type, sym_name, mod_info);
472*387f9dfdSAndroid Build Coastguard Worker if (ret == EOF && feof(f))
473*387f9dfdSAndroid Build Coastguard Worker break;
474*387f9dfdSAndroid Build Coastguard Worker if (ret < 3) {
475*387f9dfdSAndroid Build Coastguard Worker p_err("failed to read kallsyms entry: %d", ret);
476*387f9dfdSAndroid Build Coastguard Worker err = -EINVAL;
477*387f9dfdSAndroid Build Coastguard Worker goto out;
478*387f9dfdSAndroid Build Coastguard Worker }
479*387f9dfdSAndroid Build Coastguard Worker if (strcmp(func->name, sym_name) != 0)
480*387f9dfdSAndroid Build Coastguard Worker continue;
481*387f9dfdSAndroid Build Coastguard Worker func->ip = sym_addr;
482*387f9dfdSAndroid Build Coastguard Worker func->mod[0] = '\0';
483*387f9dfdSAndroid Build Coastguard Worker /* get module name from [modname] */
484*387f9dfdSAndroid Build Coastguard Worker if (ret == 4) {
485*387f9dfdSAndroid Build Coastguard Worker if (sscanf(mod_info, "%*[\t ][%[^]]", func->mod) < 1) {
486*387f9dfdSAndroid Build Coastguard Worker p_err("failed to read module name");
487*387f9dfdSAndroid Build Coastguard Worker err = -EINVAL;
488*387f9dfdSAndroid Build Coastguard Worker goto out;
489*387f9dfdSAndroid Build Coastguard Worker }
490*387f9dfdSAndroid Build Coastguard Worker }
491*387f9dfdSAndroid Build Coastguard Worker p_debug("%s = <ip %llx, mod %s>", func->name, func->ip,
492*387f9dfdSAndroid Build Coastguard Worker strlen(func->mod) > 0 ? func->mod : "vmlinux");
493*387f9dfdSAndroid Build Coastguard Worker break;
494*387f9dfdSAndroid Build Coastguard Worker }
495*387f9dfdSAndroid Build Coastguard Worker out:
496*387f9dfdSAndroid Build Coastguard Worker fclose(f);
497*387f9dfdSAndroid Build Coastguard Worker return err;
498*387f9dfdSAndroid Build Coastguard Worker }
499*387f9dfdSAndroid Build Coastguard Worker
trace_printf(void * ctx,const char * fmt,va_list args)500*387f9dfdSAndroid Build Coastguard Worker static void trace_printf(void *ctx, const char *fmt, va_list args)
501*387f9dfdSAndroid Build Coastguard Worker {
502*387f9dfdSAndroid Build Coastguard Worker vprintf(fmt, args);
503*387f9dfdSAndroid Build Coastguard Worker }
504*387f9dfdSAndroid Build Coastguard Worker
505*387f9dfdSAndroid Build Coastguard Worker #define VALID_NAME "%[A-Za-z0-9\\-_]"
506*387f9dfdSAndroid Build Coastguard Worker #define ARGDATA "%[^)]"
507*387f9dfdSAndroid Build Coastguard Worker
parse_trace(char * str,struct trace * trace)508*387f9dfdSAndroid Build Coastguard Worker static int parse_trace(char *str, struct trace *trace)
509*387f9dfdSAndroid Build Coastguard Worker {
510*387f9dfdSAndroid Build Coastguard Worker __u8 i, nr_predicates = 0, nr_entry = 0, nr_return = 0;
511*387f9dfdSAndroid Build Coastguard Worker char argname[MAX_NAME], membername[MAX_NAME];
512*387f9dfdSAndroid Build Coastguard Worker char tracestr[MAX_STR], argdata[MAX_STR];
513*387f9dfdSAndroid Build Coastguard Worker struct func *func = &trace->func;
514*387f9dfdSAndroid Build Coastguard Worker char *arg, *saveptr;
515*387f9dfdSAndroid Build Coastguard Worker int ret;
516*387f9dfdSAndroid Build Coastguard Worker
517*387f9dfdSAndroid Build Coastguard Worker copy_without_spaces(tracestr, str);
518*387f9dfdSAndroid Build Coastguard Worker
519*387f9dfdSAndroid Build Coastguard Worker p_debug("Parsing trace '%s'", tracestr);
520*387f9dfdSAndroid Build Coastguard Worker
521*387f9dfdSAndroid Build Coastguard Worker trace->filter_pid = (__u32)filter_pid;
522*387f9dfdSAndroid Build Coastguard Worker if (filter_pid)
523*387f9dfdSAndroid Build Coastguard Worker p_debug("Using pid %lu as filter", trace->filter_pid);
524*387f9dfdSAndroid Build Coastguard Worker
525*387f9dfdSAndroid Build Coastguard Worker trace->btf = vmlinux_btf;
526*387f9dfdSAndroid Build Coastguard Worker
527*387f9dfdSAndroid Build Coastguard Worker ret = sscanf(tracestr, VALID_NAME "(" ARGDATA ")", func->name, argdata);
528*387f9dfdSAndroid Build Coastguard Worker if (ret <= 0)
529*387f9dfdSAndroid Build Coastguard Worker usage();
530*387f9dfdSAndroid Build Coastguard Worker if (ret == 1) {
531*387f9dfdSAndroid Build Coastguard Worker if (strlen(tracestr) > strlen(func->name)) {
532*387f9dfdSAndroid Build Coastguard Worker p_err("Invalid function specification '%s'", tracestr);
533*387f9dfdSAndroid Build Coastguard Worker usage();
534*387f9dfdSAndroid Build Coastguard Worker }
535*387f9dfdSAndroid Build Coastguard Worker argdata[0] = '\0';
536*387f9dfdSAndroid Build Coastguard Worker p_debug("got func '%s'", func->name);
537*387f9dfdSAndroid Build Coastguard Worker } else {
538*387f9dfdSAndroid Build Coastguard Worker if (strlen(tracestr) >
539*387f9dfdSAndroid Build Coastguard Worker strlen(func->name) + strlen(argdata) + 2) {
540*387f9dfdSAndroid Build Coastguard Worker p_err("Invalid function specification '%s'", tracestr);
541*387f9dfdSAndroid Build Coastguard Worker usage();
542*387f9dfdSAndroid Build Coastguard Worker }
543*387f9dfdSAndroid Build Coastguard Worker p_debug("got func '%s', args '%s'", func->name, argdata);
544*387f9dfdSAndroid Build Coastguard Worker trace->flags |= KSNOOP_F_CUSTOM;
545*387f9dfdSAndroid Build Coastguard Worker }
546*387f9dfdSAndroid Build Coastguard Worker
547*387f9dfdSAndroid Build Coastguard Worker ret = get_func_ip_mod(func);
548*387f9dfdSAndroid Build Coastguard Worker if (ret) {
549*387f9dfdSAndroid Build Coastguard Worker p_err("could not get address of '%s'", func->name);
550*387f9dfdSAndroid Build Coastguard Worker return ret;
551*387f9dfdSAndroid Build Coastguard Worker }
552*387f9dfdSAndroid Build Coastguard Worker trace->btf = get_btf(func->mod);
553*387f9dfdSAndroid Build Coastguard Worker if (!trace->btf) {
554*387f9dfdSAndroid Build Coastguard Worker ret = -errno;
555*387f9dfdSAndroid Build Coastguard Worker p_err("could not get BTF for '%s': %s",
556*387f9dfdSAndroid Build Coastguard Worker strlen(func->mod) ? func->mod : "vmlinux",
557*387f9dfdSAndroid Build Coastguard Worker strerror(-ret));
558*387f9dfdSAndroid Build Coastguard Worker return -ENOENT;
559*387f9dfdSAndroid Build Coastguard Worker }
560*387f9dfdSAndroid Build Coastguard Worker trace->dump = btf_dump__new(trace->btf, trace_printf, NULL, NULL);
561*387f9dfdSAndroid Build Coastguard Worker if (!trace->dump) {
562*387f9dfdSAndroid Build Coastguard Worker ret = -errno;
563*387f9dfdSAndroid Build Coastguard Worker p_err("could not create BTF dump : %s", strerror(-ret));
564*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
565*387f9dfdSAndroid Build Coastguard Worker }
566*387f9dfdSAndroid Build Coastguard Worker
567*387f9dfdSAndroid Build Coastguard Worker ret = get_func_btf(trace->btf, func);
568*387f9dfdSAndroid Build Coastguard Worker if (ret) {
569*387f9dfdSAndroid Build Coastguard Worker p_debug("unexpected return value '%d' getting function", ret);
570*387f9dfdSAndroid Build Coastguard Worker return ret;
571*387f9dfdSAndroid Build Coastguard Worker }
572*387f9dfdSAndroid Build Coastguard Worker
573*387f9dfdSAndroid Build Coastguard Worker for (arg = strtok_r(argdata, ",", &saveptr), i = 0;
574*387f9dfdSAndroid Build Coastguard Worker arg;
575*387f9dfdSAndroid Build Coastguard Worker arg = strtok_r(NULL, ",", &saveptr), i++) {
576*387f9dfdSAndroid Build Coastguard Worker char *predicate = NULL;
577*387f9dfdSAndroid Build Coastguard Worker
578*387f9dfdSAndroid Build Coastguard Worker ret = sscanf(arg, VALID_NAME "->" VALID_NAME,
579*387f9dfdSAndroid Build Coastguard Worker argname, membername);
580*387f9dfdSAndroid Build Coastguard Worker if (ret == 2) {
581*387f9dfdSAndroid Build Coastguard Worker if (strlen(arg) >
582*387f9dfdSAndroid Build Coastguard Worker strlen(argname) + strlen(membername) + 2) {
583*387f9dfdSAndroid Build Coastguard Worker predicate = arg + strlen(argname) +
584*387f9dfdSAndroid Build Coastguard Worker strlen(membername) + 2;
585*387f9dfdSAndroid Build Coastguard Worker }
586*387f9dfdSAndroid Build Coastguard Worker p_debug("'%s' dereferences '%s', predicate '%s'",
587*387f9dfdSAndroid Build Coastguard Worker argname, membername, predicate);
588*387f9dfdSAndroid Build Coastguard Worker } else {
589*387f9dfdSAndroid Build Coastguard Worker if (strlen(arg) > strlen(argname))
590*387f9dfdSAndroid Build Coastguard Worker predicate = arg + strlen(argname);
591*387f9dfdSAndroid Build Coastguard Worker p_debug("'%s' arg, predcate '%s'", argname, predicate);
592*387f9dfdSAndroid Build Coastguard Worker membername[0] = '\0';
593*387f9dfdSAndroid Build Coastguard Worker }
594*387f9dfdSAndroid Build Coastguard Worker
595*387f9dfdSAndroid Build Coastguard Worker if (i >= MAX_TRACES) {
596*387f9dfdSAndroid Build Coastguard Worker p_err("Too many arguments; up to %d are supported",
597*387f9dfdSAndroid Build Coastguard Worker MAX_TRACES);
598*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
599*387f9dfdSAndroid Build Coastguard Worker }
600*387f9dfdSAndroid Build Coastguard Worker if (trace_to_value(trace->btf, func, argname, membername,
601*387f9dfdSAndroid Build Coastguard Worker predicate, &trace->traces[i]))
602*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
603*387f9dfdSAndroid Build Coastguard Worker
604*387f9dfdSAndroid Build Coastguard Worker if (predicate)
605*387f9dfdSAndroid Build Coastguard Worker nr_predicates++;
606*387f9dfdSAndroid Build Coastguard Worker if (trace->traces[i].base_arg == KSNOOP_RETURN)
607*387f9dfdSAndroid Build Coastguard Worker nr_return++;
608*387f9dfdSAndroid Build Coastguard Worker else
609*387f9dfdSAndroid Build Coastguard Worker nr_entry++;
610*387f9dfdSAndroid Build Coastguard Worker trace->nr_traces++;
611*387f9dfdSAndroid Build Coastguard Worker }
612*387f9dfdSAndroid Build Coastguard Worker
613*387f9dfdSAndroid Build Coastguard Worker if (trace->nr_traces > 0) {
614*387f9dfdSAndroid Build Coastguard Worker trace->flags |= KSNOOP_F_CUSTOM;
615*387f9dfdSAndroid Build Coastguard Worker p_debug("custom trace with %d args", trace->nr_traces);
616*387f9dfdSAndroid Build Coastguard Worker
617*387f9dfdSAndroid Build Coastguard Worker /* If we have one or more predicates _and_ references to
618*387f9dfdSAndroid Build Coastguard Worker * entry and return values, we need to activate "stash"
619*387f9dfdSAndroid Build Coastguard Worker * mode where arg traces are stored on entry and not
620*387f9dfdSAndroid Build Coastguard Worker * sent until return to ensure predicates are satisfied.
621*387f9dfdSAndroid Build Coastguard Worker */
622*387f9dfdSAndroid Build Coastguard Worker if (nr_predicates > 0 && nr_entry > 0 && nr_return > 0) {
623*387f9dfdSAndroid Build Coastguard Worker trace->flags |= KSNOOP_F_STASH;
624*387f9dfdSAndroid Build Coastguard Worker p_debug("activating stash mode on entry");
625*387f9dfdSAndroid Build Coastguard Worker }
626*387f9dfdSAndroid Build Coastguard Worker } else {
627*387f9dfdSAndroid Build Coastguard Worker p_debug("Standard trace, function with %d arguments",
628*387f9dfdSAndroid Build Coastguard Worker func->nr_args);
629*387f9dfdSAndroid Build Coastguard Worker /* copy function arg/return value to trace specification. */
630*387f9dfdSAndroid Build Coastguard Worker memcpy(trace->traces, func->args, sizeof(trace->traces));
631*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < MAX_TRACES; i++)
632*387f9dfdSAndroid Build Coastguard Worker trace->traces[i].base_arg = i;
633*387f9dfdSAndroid Build Coastguard Worker trace->nr_traces = MAX_TRACES;
634*387f9dfdSAndroid Build Coastguard Worker }
635*387f9dfdSAndroid Build Coastguard Worker
636*387f9dfdSAndroid Build Coastguard Worker return 0;
637*387f9dfdSAndroid Build Coastguard Worker }
638*387f9dfdSAndroid Build Coastguard Worker
parse_traces(int argc,char ** argv,struct trace ** traces)639*387f9dfdSAndroid Build Coastguard Worker static int parse_traces(int argc, char **argv, struct trace **traces)
640*387f9dfdSAndroid Build Coastguard Worker {
641*387f9dfdSAndroid Build Coastguard Worker __u8 i;
642*387f9dfdSAndroid Build Coastguard Worker
643*387f9dfdSAndroid Build Coastguard Worker if (argc == 0)
644*387f9dfdSAndroid Build Coastguard Worker usage();
645*387f9dfdSAndroid Build Coastguard Worker
646*387f9dfdSAndroid Build Coastguard Worker if (argc > MAX_FUNC_TRACES) {
647*387f9dfdSAndroid Build Coastguard Worker p_err("A maximum of %d traces are supported", MAX_FUNC_TRACES);
648*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
649*387f9dfdSAndroid Build Coastguard Worker }
650*387f9dfdSAndroid Build Coastguard Worker *traces = calloc(argc, sizeof(struct trace));
651*387f9dfdSAndroid Build Coastguard Worker if (!*traces) {
652*387f9dfdSAndroid Build Coastguard Worker p_err("Could not allocate %d traces", argc);
653*387f9dfdSAndroid Build Coastguard Worker return -ENOMEM;
654*387f9dfdSAndroid Build Coastguard Worker }
655*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < argc; i++) {
656*387f9dfdSAndroid Build Coastguard Worker if (parse_trace(argv[i], &((*traces)[i])))
657*387f9dfdSAndroid Build Coastguard Worker return -EINVAL;
658*387f9dfdSAndroid Build Coastguard Worker if (!stack_mode || i == 0)
659*387f9dfdSAndroid Build Coastguard Worker continue;
660*387f9dfdSAndroid Build Coastguard Worker /* tell stack mode trace which function to expect next */
661*387f9dfdSAndroid Build Coastguard Worker (*traces)[i].prev_ip = (*traces)[i-1].func.ip;
662*387f9dfdSAndroid Build Coastguard Worker (*traces)[i-1].next_ip = (*traces)[i].func.ip;
663*387f9dfdSAndroid Build Coastguard Worker }
664*387f9dfdSAndroid Build Coastguard Worker return i;
665*387f9dfdSAndroid Build Coastguard Worker }
666*387f9dfdSAndroid Build Coastguard Worker
cmd_info(int argc,char ** argv)667*387f9dfdSAndroid Build Coastguard Worker static int cmd_info(int argc, char **argv)
668*387f9dfdSAndroid Build Coastguard Worker {
669*387f9dfdSAndroid Build Coastguard Worker struct trace *traces = NULL;
670*387f9dfdSAndroid Build Coastguard Worker char str[MAX_STR];
671*387f9dfdSAndroid Build Coastguard Worker int nr_traces;
672*387f9dfdSAndroid Build Coastguard Worker __u8 i, j;
673*387f9dfdSAndroid Build Coastguard Worker
674*387f9dfdSAndroid Build Coastguard Worker nr_traces = parse_traces(argc, argv, &traces);
675*387f9dfdSAndroid Build Coastguard Worker if (nr_traces < 0)
676*387f9dfdSAndroid Build Coastguard Worker return nr_traces;
677*387f9dfdSAndroid Build Coastguard Worker
678*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < nr_traces; i++) {
679*387f9dfdSAndroid Build Coastguard Worker struct func *func = &traces[i].func;
680*387f9dfdSAndroid Build Coastguard Worker
681*387f9dfdSAndroid Build Coastguard Worker printf("%s%s(",
682*387f9dfdSAndroid Build Coastguard Worker value_to_str(traces[i].btf, &func->args[KSNOOP_RETURN],
683*387f9dfdSAndroid Build Coastguard Worker str),
684*387f9dfdSAndroid Build Coastguard Worker func->name);
685*387f9dfdSAndroid Build Coastguard Worker for (j = 0; j < func->nr_args; j++) {
686*387f9dfdSAndroid Build Coastguard Worker if (j > 0)
687*387f9dfdSAndroid Build Coastguard Worker printf(", ");
688*387f9dfdSAndroid Build Coastguard Worker printf("%s", value_to_str(traces[i].btf, &func->args[j],
689*387f9dfdSAndroid Build Coastguard Worker str));
690*387f9dfdSAndroid Build Coastguard Worker }
691*387f9dfdSAndroid Build Coastguard Worker if (func->nr_args > MAX_ARGS)
692*387f9dfdSAndroid Build Coastguard Worker printf(" /* and %d more args that are not traceable */",
693*387f9dfdSAndroid Build Coastguard Worker func->nr_args - MAX_ARGS);
694*387f9dfdSAndroid Build Coastguard Worker printf(");\n");
695*387f9dfdSAndroid Build Coastguard Worker }
696*387f9dfdSAndroid Build Coastguard Worker free(traces);
697*387f9dfdSAndroid Build Coastguard Worker return 0;
698*387f9dfdSAndroid Build Coastguard Worker }
699*387f9dfdSAndroid Build Coastguard Worker
trace_handler(void * ctx,int cpu,void * data,__u32 size)700*387f9dfdSAndroid Build Coastguard Worker static void trace_handler(void *ctx, int cpu, void *data, __u32 size)
701*387f9dfdSAndroid Build Coastguard Worker {
702*387f9dfdSAndroid Build Coastguard Worker struct trace *trace = data;
703*387f9dfdSAndroid Build Coastguard Worker int i, shown, ret;
704*387f9dfdSAndroid Build Coastguard Worker
705*387f9dfdSAndroid Build Coastguard Worker p_debug("got trace, size %d", size);
706*387f9dfdSAndroid Build Coastguard Worker if (size < (sizeof(*trace) - MAX_TRACE_BUF)) {
707*387f9dfdSAndroid Build Coastguard Worker p_err("\t/* trace buffer size '%u' < min %ld */",
708*387f9dfdSAndroid Build Coastguard Worker size, sizeof(trace) - MAX_TRACE_BUF);
709*387f9dfdSAndroid Build Coastguard Worker return;
710*387f9dfdSAndroid Build Coastguard Worker }
711*387f9dfdSAndroid Build Coastguard Worker printf("%16lld %4d %8u %s(\n", trace->time, trace->cpu, trace->pid,
712*387f9dfdSAndroid Build Coastguard Worker trace->func.name);
713*387f9dfdSAndroid Build Coastguard Worker
714*387f9dfdSAndroid Build Coastguard Worker for (i = 0, shown = 0; i < trace->nr_traces; i++) {
715*387f9dfdSAndroid Build Coastguard Worker DECLARE_LIBBPF_OPTS(btf_dump_type_data_opts, opts);
716*387f9dfdSAndroid Build Coastguard Worker bool entry = trace->data_flags & KSNOOP_F_ENTRY;
717*387f9dfdSAndroid Build Coastguard Worker struct value *val = &trace->traces[i];
718*387f9dfdSAndroid Build Coastguard Worker struct trace_data *data = &trace->trace_data[i];
719*387f9dfdSAndroid Build Coastguard Worker
720*387f9dfdSAndroid Build Coastguard Worker opts.indent_level = 36;
721*387f9dfdSAndroid Build Coastguard Worker opts.indent_str = " ";
722*387f9dfdSAndroid Build Coastguard Worker
723*387f9dfdSAndroid Build Coastguard Worker /* skip if it's entry data and trace data is for return, or
724*387f9dfdSAndroid Build Coastguard Worker * if it's return and trace data is entry; only exception in
725*387f9dfdSAndroid Build Coastguard Worker * the latter case is if we stashed data; in such cases we
726*387f9dfdSAndroid Build Coastguard Worker * want to see it as it's a mix of entry/return data with
727*387f9dfdSAndroid Build Coastguard Worker * predicates.
728*387f9dfdSAndroid Build Coastguard Worker */
729*387f9dfdSAndroid Build Coastguard Worker if ((entry && !base_arg_is_entry(val->base_arg)) ||
730*387f9dfdSAndroid Build Coastguard Worker (!entry && base_arg_is_entry(val->base_arg) &&
731*387f9dfdSAndroid Build Coastguard Worker !(trace->flags & KSNOOP_F_STASH)))
732*387f9dfdSAndroid Build Coastguard Worker continue;
733*387f9dfdSAndroid Build Coastguard Worker
734*387f9dfdSAndroid Build Coastguard Worker if (val->type_id == 0)
735*387f9dfdSAndroid Build Coastguard Worker continue;
736*387f9dfdSAndroid Build Coastguard Worker
737*387f9dfdSAndroid Build Coastguard Worker if (shown > 0)
738*387f9dfdSAndroid Build Coastguard Worker printf(",\n");
739*387f9dfdSAndroid Build Coastguard Worker printf("%34s %s = ", "", val->name);
740*387f9dfdSAndroid Build Coastguard Worker if (val->flags & KSNOOP_F_PTR)
741*387f9dfdSAndroid Build Coastguard Worker printf("*(0x%llx)", data->raw_value);
742*387f9dfdSAndroid Build Coastguard Worker printf("\n");
743*387f9dfdSAndroid Build Coastguard Worker
744*387f9dfdSAndroid Build Coastguard Worker if (data->err_type_id != 0) {
745*387f9dfdSAndroid Build Coastguard Worker char typestr[MAX_STR];
746*387f9dfdSAndroid Build Coastguard Worker
747*387f9dfdSAndroid Build Coastguard Worker printf("%36s /* Cannot show '%s' as '%s%s'; invalid/userspace ptr? */\n",
748*387f9dfdSAndroid Build Coastguard Worker "",
749*387f9dfdSAndroid Build Coastguard Worker val->name,
750*387f9dfdSAndroid Build Coastguard Worker type_id_to_str(trace->btf,
751*387f9dfdSAndroid Build Coastguard Worker val->type_id,
752*387f9dfdSAndroid Build Coastguard Worker typestr),
753*387f9dfdSAndroid Build Coastguard Worker val->flags & KSNOOP_F_PTR ?
754*387f9dfdSAndroid Build Coastguard Worker " *" : "");
755*387f9dfdSAndroid Build Coastguard Worker } else {
756*387f9dfdSAndroid Build Coastguard Worker ret = btf_dump__dump_type_data
757*387f9dfdSAndroid Build Coastguard Worker (trace->dump, val->type_id,
758*387f9dfdSAndroid Build Coastguard Worker trace->buf + data->buf_offset,
759*387f9dfdSAndroid Build Coastguard Worker data->buf_len, &opts);
760*387f9dfdSAndroid Build Coastguard Worker /* truncated? */
761*387f9dfdSAndroid Build Coastguard Worker if (ret == -E2BIG)
762*387f9dfdSAndroid Build Coastguard Worker printf("%36s... /* %d bytes of %d */", "",
763*387f9dfdSAndroid Build Coastguard Worker data->buf_len,
764*387f9dfdSAndroid Build Coastguard Worker val->size);
765*387f9dfdSAndroid Build Coastguard Worker }
766*387f9dfdSAndroid Build Coastguard Worker shown++;
767*387f9dfdSAndroid Build Coastguard Worker
768*387f9dfdSAndroid Build Coastguard Worker }
769*387f9dfdSAndroid Build Coastguard Worker printf("\n%31s);\n\n", "");
770*387f9dfdSAndroid Build Coastguard Worker fflush(stdout);
771*387f9dfdSAndroid Build Coastguard Worker }
772*387f9dfdSAndroid Build Coastguard Worker
lost_handler(void * ctx,int cpu,__u64 cnt)773*387f9dfdSAndroid Build Coastguard Worker static void lost_handler(void *ctx, int cpu, __u64 cnt)
774*387f9dfdSAndroid Build Coastguard Worker {
775*387f9dfdSAndroid Build Coastguard Worker p_err("\t/* lost %llu events */", cnt);
776*387f9dfdSAndroid Build Coastguard Worker }
777*387f9dfdSAndroid Build Coastguard Worker
sig_int(int signo)778*387f9dfdSAndroid Build Coastguard Worker static void sig_int(int signo)
779*387f9dfdSAndroid Build Coastguard Worker {
780*387f9dfdSAndroid Build Coastguard Worker exiting = 1;
781*387f9dfdSAndroid Build Coastguard Worker }
782*387f9dfdSAndroid Build Coastguard Worker
add_traces(struct bpf_map * func_map,struct trace * traces,int nr_traces)783*387f9dfdSAndroid Build Coastguard Worker static int add_traces(struct bpf_map *func_map, struct trace *traces,
784*387f9dfdSAndroid Build Coastguard Worker int nr_traces)
785*387f9dfdSAndroid Build Coastguard Worker {
786*387f9dfdSAndroid Build Coastguard Worker int i, j, ret, nr_cpus = libbpf_num_possible_cpus();
787*387f9dfdSAndroid Build Coastguard Worker struct trace *map_traces;
788*387f9dfdSAndroid Build Coastguard Worker
789*387f9dfdSAndroid Build Coastguard Worker map_traces = calloc(nr_cpus, sizeof(struct trace));
790*387f9dfdSAndroid Build Coastguard Worker if (!map_traces) {
791*387f9dfdSAndroid Build Coastguard Worker p_err("Could not allocate memory for %d traces", nr_traces);
792*387f9dfdSAndroid Build Coastguard Worker return -ENOMEM;
793*387f9dfdSAndroid Build Coastguard Worker }
794*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < nr_traces; i++) {
795*387f9dfdSAndroid Build Coastguard Worker for (j = 0; j < nr_cpus; j++)
796*387f9dfdSAndroid Build Coastguard Worker memcpy(&map_traces[j], &traces[i],
797*387f9dfdSAndroid Build Coastguard Worker sizeof(map_traces[j]));
798*387f9dfdSAndroid Build Coastguard Worker
799*387f9dfdSAndroid Build Coastguard Worker ret = bpf_map_update_elem(bpf_map__fd(func_map),
800*387f9dfdSAndroid Build Coastguard Worker &traces[i].func.ip,
801*387f9dfdSAndroid Build Coastguard Worker map_traces,
802*387f9dfdSAndroid Build Coastguard Worker BPF_NOEXIST);
803*387f9dfdSAndroid Build Coastguard Worker if (ret) {
804*387f9dfdSAndroid Build Coastguard Worker p_err("Could not add map entry for '%s': %s",
805*387f9dfdSAndroid Build Coastguard Worker traces[i].func.name, strerror(-ret));
806*387f9dfdSAndroid Build Coastguard Worker break;
807*387f9dfdSAndroid Build Coastguard Worker }
808*387f9dfdSAndroid Build Coastguard Worker }
809*387f9dfdSAndroid Build Coastguard Worker free(map_traces);
810*387f9dfdSAndroid Build Coastguard Worker return ret;
811*387f9dfdSAndroid Build Coastguard Worker }
812*387f9dfdSAndroid Build Coastguard Worker
attach_traces(struct ksnoop_bpf * skel,struct trace * traces,int nr_traces)813*387f9dfdSAndroid Build Coastguard Worker static int attach_traces(struct ksnoop_bpf *skel, struct trace *traces,
814*387f9dfdSAndroid Build Coastguard Worker int nr_traces)
815*387f9dfdSAndroid Build Coastguard Worker {
816*387f9dfdSAndroid Build Coastguard Worker int i, ret;
817*387f9dfdSAndroid Build Coastguard Worker
818*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < nr_traces; i++) {
819*387f9dfdSAndroid Build Coastguard Worker traces[i].links[0] =
820*387f9dfdSAndroid Build Coastguard Worker bpf_program__attach_kprobe(skel->progs.kprobe_entry,
821*387f9dfdSAndroid Build Coastguard Worker false,
822*387f9dfdSAndroid Build Coastguard Worker traces[i].func.name);
823*387f9dfdSAndroid Build Coastguard Worker if (!traces[i].links[0]) {
824*387f9dfdSAndroid Build Coastguard Worker ret = -errno;
825*387f9dfdSAndroid Build Coastguard Worker p_err("Could not attach kprobe to '%s': %s",
826*387f9dfdSAndroid Build Coastguard Worker traces[i].func.name, strerror(-ret));
827*387f9dfdSAndroid Build Coastguard Worker return ret;
828*387f9dfdSAndroid Build Coastguard Worker }
829*387f9dfdSAndroid Build Coastguard Worker p_debug("Attached kprobe for '%s'", traces[i].func.name);
830*387f9dfdSAndroid Build Coastguard Worker
831*387f9dfdSAndroid Build Coastguard Worker traces[i].links[1] =
832*387f9dfdSAndroid Build Coastguard Worker bpf_program__attach_kprobe(skel->progs.kprobe_return,
833*387f9dfdSAndroid Build Coastguard Worker true,
834*387f9dfdSAndroid Build Coastguard Worker traces[i].func.name);
835*387f9dfdSAndroid Build Coastguard Worker if (!traces[i].links[1]) {
836*387f9dfdSAndroid Build Coastguard Worker ret = -errno;
837*387f9dfdSAndroid Build Coastguard Worker p_err("Could not attach kretprobe to '%s': %s",
838*387f9dfdSAndroid Build Coastguard Worker traces[i].func.name, strerror(-ret));
839*387f9dfdSAndroid Build Coastguard Worker return ret;
840*387f9dfdSAndroid Build Coastguard Worker }
841*387f9dfdSAndroid Build Coastguard Worker p_debug("Attached kretprobe for '%s'", traces[i].func.name);
842*387f9dfdSAndroid Build Coastguard Worker }
843*387f9dfdSAndroid Build Coastguard Worker return 0;
844*387f9dfdSAndroid Build Coastguard Worker }
845*387f9dfdSAndroid Build Coastguard Worker
cmd_trace(int argc,char ** argv)846*387f9dfdSAndroid Build Coastguard Worker static int cmd_trace(int argc, char **argv)
847*387f9dfdSAndroid Build Coastguard Worker {
848*387f9dfdSAndroid Build Coastguard Worker struct bpf_map *perf_map, *func_map;
849*387f9dfdSAndroid Build Coastguard Worker struct perf_buffer *pb = NULL;
850*387f9dfdSAndroid Build Coastguard Worker struct ksnoop_bpf *skel;
851*387f9dfdSAndroid Build Coastguard Worker int i, nr_traces, ret = -1;
852*387f9dfdSAndroid Build Coastguard Worker struct trace *traces = NULL;
853*387f9dfdSAndroid Build Coastguard Worker
854*387f9dfdSAndroid Build Coastguard Worker nr_traces = parse_traces(argc, argv, &traces);
855*387f9dfdSAndroid Build Coastguard Worker if (nr_traces < 0)
856*387f9dfdSAndroid Build Coastguard Worker return nr_traces;
857*387f9dfdSAndroid Build Coastguard Worker
858*387f9dfdSAndroid Build Coastguard Worker skel = ksnoop_bpf__open_and_load();
859*387f9dfdSAndroid Build Coastguard Worker if (!skel) {
860*387f9dfdSAndroid Build Coastguard Worker ret = -errno;
861*387f9dfdSAndroid Build Coastguard Worker p_err("Could not load ksnoop BPF: %s", strerror(-ret));
862*387f9dfdSAndroid Build Coastguard Worker return 1;
863*387f9dfdSAndroid Build Coastguard Worker }
864*387f9dfdSAndroid Build Coastguard Worker
865*387f9dfdSAndroid Build Coastguard Worker perf_map = skel->maps.ksnoop_perf_map;
866*387f9dfdSAndroid Build Coastguard Worker if (!perf_map) {
867*387f9dfdSAndroid Build Coastguard Worker p_err("Could not find '%s'", "ksnoop_perf_map");
868*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
869*387f9dfdSAndroid Build Coastguard Worker }
870*387f9dfdSAndroid Build Coastguard Worker func_map = bpf_object__find_map_by_name(skel->obj, "ksnoop_func_map");
871*387f9dfdSAndroid Build Coastguard Worker if (!func_map) {
872*387f9dfdSAndroid Build Coastguard Worker p_err("Could not find '%s'", "ksnoop_func_map");
873*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
874*387f9dfdSAndroid Build Coastguard Worker }
875*387f9dfdSAndroid Build Coastguard Worker
876*387f9dfdSAndroid Build Coastguard Worker if (add_traces(func_map, traces, nr_traces)) {
877*387f9dfdSAndroid Build Coastguard Worker p_err("Could not add traces to '%s'", "ksnoop_func_map");
878*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
879*387f9dfdSAndroid Build Coastguard Worker }
880*387f9dfdSAndroid Build Coastguard Worker
881*387f9dfdSAndroid Build Coastguard Worker if (attach_traces(skel, traces, nr_traces)) {
882*387f9dfdSAndroid Build Coastguard Worker p_err("Could not attach %d traces", nr_traces);
883*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
884*387f9dfdSAndroid Build Coastguard Worker }
885*387f9dfdSAndroid Build Coastguard Worker
886*387f9dfdSAndroid Build Coastguard Worker pb = perf_buffer__new(bpf_map__fd(perf_map), pages,
887*387f9dfdSAndroid Build Coastguard Worker trace_handler, lost_handler, NULL, NULL);
888*387f9dfdSAndroid Build Coastguard Worker if (!pb) {
889*387f9dfdSAndroid Build Coastguard Worker ret = -errno;
890*387f9dfdSAndroid Build Coastguard Worker p_err("Could not create perf buffer: %s", strerror(-ret));
891*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
892*387f9dfdSAndroid Build Coastguard Worker }
893*387f9dfdSAndroid Build Coastguard Worker
894*387f9dfdSAndroid Build Coastguard Worker printf("%16s %4s %8s %s\n", "TIME", "CPU", "PID", "FUNCTION/ARGS");
895*387f9dfdSAndroid Build Coastguard Worker
896*387f9dfdSAndroid Build Coastguard Worker if (signal(SIGINT, sig_int) == SIG_ERR) {
897*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
898*387f9dfdSAndroid Build Coastguard Worker ret = 1;
899*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
900*387f9dfdSAndroid Build Coastguard Worker }
901*387f9dfdSAndroid Build Coastguard Worker
902*387f9dfdSAndroid Build Coastguard Worker while (!exiting) {
903*387f9dfdSAndroid Build Coastguard Worker ret = perf_buffer__poll(pb, 1);
904*387f9dfdSAndroid Build Coastguard Worker if (ret < 0 && ret != -EINTR) {
905*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "error polling perf buffer: %s\n", strerror(-ret));
906*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
907*387f9dfdSAndroid Build Coastguard Worker }
908*387f9dfdSAndroid Build Coastguard Worker /* reset ret to return 0 if exiting */
909*387f9dfdSAndroid Build Coastguard Worker ret = 0;
910*387f9dfdSAndroid Build Coastguard Worker }
911*387f9dfdSAndroid Build Coastguard Worker
912*387f9dfdSAndroid Build Coastguard Worker cleanup:
913*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < nr_traces; i++) {
914*387f9dfdSAndroid Build Coastguard Worker bpf_link__destroy(traces[i].links[0]);
915*387f9dfdSAndroid Build Coastguard Worker bpf_link__destroy(traces[i].links[1]);
916*387f9dfdSAndroid Build Coastguard Worker }
917*387f9dfdSAndroid Build Coastguard Worker free(traces);
918*387f9dfdSAndroid Build Coastguard Worker perf_buffer__free(pb);
919*387f9dfdSAndroid Build Coastguard Worker ksnoop_bpf__destroy(skel);
920*387f9dfdSAndroid Build Coastguard Worker
921*387f9dfdSAndroid Build Coastguard Worker return ret;
922*387f9dfdSAndroid Build Coastguard Worker }
923*387f9dfdSAndroid Build Coastguard Worker
924*387f9dfdSAndroid Build Coastguard Worker struct cmd {
925*387f9dfdSAndroid Build Coastguard Worker const char *cmd;
926*387f9dfdSAndroid Build Coastguard Worker int (*func)(int argc, char **argv);
927*387f9dfdSAndroid Build Coastguard Worker };
928*387f9dfdSAndroid Build Coastguard Worker
929*387f9dfdSAndroid Build Coastguard Worker struct cmd cmds[] = {
930*387f9dfdSAndroid Build Coastguard Worker { "info", cmd_info },
931*387f9dfdSAndroid Build Coastguard Worker { "trace", cmd_trace },
932*387f9dfdSAndroid Build Coastguard Worker { "help", cmd_help },
933*387f9dfdSAndroid Build Coastguard Worker { NULL, NULL }
934*387f9dfdSAndroid Build Coastguard Worker };
935*387f9dfdSAndroid Build Coastguard Worker
cmd_select(int argc,char ** argv)936*387f9dfdSAndroid Build Coastguard Worker static int cmd_select(int argc, char **argv)
937*387f9dfdSAndroid Build Coastguard Worker {
938*387f9dfdSAndroid Build Coastguard Worker int i;
939*387f9dfdSAndroid Build Coastguard Worker
940*387f9dfdSAndroid Build Coastguard Worker for (i = 0; cmds[i].cmd; i++) {
941*387f9dfdSAndroid Build Coastguard Worker if (strncmp(*argv, cmds[i].cmd, strlen(*argv)) == 0)
942*387f9dfdSAndroid Build Coastguard Worker return cmds[i].func(argc - 1, argv + 1);
943*387f9dfdSAndroid Build Coastguard Worker }
944*387f9dfdSAndroid Build Coastguard Worker return cmd_trace(argc, argv);
945*387f9dfdSAndroid Build Coastguard Worker }
946*387f9dfdSAndroid Build Coastguard Worker
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)947*387f9dfdSAndroid Build Coastguard Worker static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
948*387f9dfdSAndroid Build Coastguard Worker {
949*387f9dfdSAndroid Build Coastguard Worker if (level == LIBBPF_DEBUG && !verbose)
950*387f9dfdSAndroid Build Coastguard Worker return 0;
951*387f9dfdSAndroid Build Coastguard Worker return vfprintf(stderr, format, args);
952*387f9dfdSAndroid Build Coastguard Worker }
953*387f9dfdSAndroid Build Coastguard Worker
main(int argc,char * argv[])954*387f9dfdSAndroid Build Coastguard Worker int main(int argc, char *argv[])
955*387f9dfdSAndroid Build Coastguard Worker {
956*387f9dfdSAndroid Build Coastguard Worker static const struct option options[] = {
957*387f9dfdSAndroid Build Coastguard Worker { "debug", no_argument, NULL, 'd' },
958*387f9dfdSAndroid Build Coastguard Worker { "verbose", no_argument, NULL, 'v' },
959*387f9dfdSAndroid Build Coastguard Worker { "help", no_argument, NULL, 'h' },
960*387f9dfdSAndroid Build Coastguard Worker { "version", no_argument, NULL, 'V' },
961*387f9dfdSAndroid Build Coastguard Worker { "pages", required_argument, NULL, 'P' },
962*387f9dfdSAndroid Build Coastguard Worker { "pid", required_argument, NULL, 'p' },
963*387f9dfdSAndroid Build Coastguard Worker { 0 }
964*387f9dfdSAndroid Build Coastguard Worker };
965*387f9dfdSAndroid Build Coastguard Worker int opt;
966*387f9dfdSAndroid Build Coastguard Worker
967*387f9dfdSAndroid Build Coastguard Worker bin_name = argv[0];
968*387f9dfdSAndroid Build Coastguard Worker
969*387f9dfdSAndroid Build Coastguard Worker while ((opt = getopt_long(argc, argv, "dvhp:P:sV", options,
970*387f9dfdSAndroid Build Coastguard Worker NULL)) >= 0) {
971*387f9dfdSAndroid Build Coastguard Worker switch (opt) {
972*387f9dfdSAndroid Build Coastguard Worker case 'd':
973*387f9dfdSAndroid Build Coastguard Worker verbose = true;
974*387f9dfdSAndroid Build Coastguard Worker log_level = DEBUG;
975*387f9dfdSAndroid Build Coastguard Worker break;
976*387f9dfdSAndroid Build Coastguard Worker case 'v':
977*387f9dfdSAndroid Build Coastguard Worker verbose = true;
978*387f9dfdSAndroid Build Coastguard Worker log_level = DEBUG;
979*387f9dfdSAndroid Build Coastguard Worker break;
980*387f9dfdSAndroid Build Coastguard Worker case 'h':
981*387f9dfdSAndroid Build Coastguard Worker return cmd_help(argc, argv);
982*387f9dfdSAndroid Build Coastguard Worker case 'V':
983*387f9dfdSAndroid Build Coastguard Worker return do_version(argc, argv);
984*387f9dfdSAndroid Build Coastguard Worker case 'p':
985*387f9dfdSAndroid Build Coastguard Worker filter_pid = atoi(optarg);
986*387f9dfdSAndroid Build Coastguard Worker break;
987*387f9dfdSAndroid Build Coastguard Worker case 'P':
988*387f9dfdSAndroid Build Coastguard Worker pages = atoi(optarg);
989*387f9dfdSAndroid Build Coastguard Worker break;
990*387f9dfdSAndroid Build Coastguard Worker case 's':
991*387f9dfdSAndroid Build Coastguard Worker stack_mode = true;
992*387f9dfdSAndroid Build Coastguard Worker break;
993*387f9dfdSAndroid Build Coastguard Worker default:
994*387f9dfdSAndroid Build Coastguard Worker p_err("unrecognized option '%s'", argv[optind - 1]);
995*387f9dfdSAndroid Build Coastguard Worker usage();
996*387f9dfdSAndroid Build Coastguard Worker }
997*387f9dfdSAndroid Build Coastguard Worker }
998*387f9dfdSAndroid Build Coastguard Worker if (argc == 1)
999*387f9dfdSAndroid Build Coastguard Worker usage();
1000*387f9dfdSAndroid Build Coastguard Worker argc -= optind;
1001*387f9dfdSAndroid Build Coastguard Worker argv += optind;
1002*387f9dfdSAndroid Build Coastguard Worker if (argc < 0)
1003*387f9dfdSAndroid Build Coastguard Worker usage();
1004*387f9dfdSAndroid Build Coastguard Worker
1005*387f9dfdSAndroid Build Coastguard Worker libbpf_set_print(libbpf_print_fn);
1006*387f9dfdSAndroid Build Coastguard Worker
1007*387f9dfdSAndroid Build Coastguard Worker return cmd_select(argc, argv);
1008*387f9dfdSAndroid Build Coastguard Worker }
1009