1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <bpf_helpers.h>
18 #include <linux/bpf.h>
19 #include <stdbool.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 // TODO: import this struct from generic header, access registers via generic
25 // function
26 struct pt_regs {
27   unsigned long regs[16];
28   unsigned long pc;
29   unsigned long pr;
30   unsigned long sr;
31   unsigned long gbr;
32   unsigned long mach;
33   unsigned long macl;
34   long tra;
35 };
36 
37 // TODO: share this struct between bpf and uprobestats
38 struct CallResult {
39   unsigned long pc;
40   unsigned long regs[10];
41 };
42 
43 struct CallTimestamp {
44   unsigned int event;
45   unsigned long timestampNs;
46 };
47 
48 DEFINE_BPF_RINGBUF_EXT(call_detail_buf, struct CallResult, 4096,
49                        AID_UPROBESTATS, AID_UPROBESTATS, 0600, "", "", PRIVATE,
50                        BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG,
51                        LOAD_ON_USER, LOAD_ON_USERDEBUG);
52 
53 DEFINE_BPF_RINGBUF_EXT(call_timestamp_buf, struct CallTimestamp, 4096,
54                        AID_UPROBESTATS, AID_UPROBESTATS, 0600, "", "", PRIVATE,
55                        BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG,
56                        LOAD_ON_USER, LOAD_ON_USERDEBUG);
57 
58 DEFINE_BPF_PROG("uprobe/call_detail", AID_UPROBESTATS, AID_UPROBESTATS,
59                 BPF_KPROBE11)
60 (struct pt_regs *ctx) {
61   struct CallResult result;
62   // for whatever reason, reading past register 10 causes bpf verifier to fail
63   for (int i = 0; i < 11; i++) {
64     result.regs[i] = ctx->regs[i];
65   }
66   result.pc = ctx->pc;
67   struct CallResult *output = bpf_call_detail_buf_reserve();
68   if (output == NULL)
69     return 1;
70   (*output) = result;
71   bpf_call_detail_buf_submit(output);
72   return 0;
73 }
74 
75 DEFINE_BPF_PROG("uprobe/call_timestamp_1", AID_UPROBESTATS, AID_UPROBESTATS,
76                 BPF_KPROBE1)
77 () {
78   struct CallTimestamp result;
79   result.event = 1;
80   result.timestampNs = bpf_ktime_get_ns();
81   struct CallTimestamp *output = bpf_call_timestamp_buf_reserve();
82   if (output == NULL) {
83     return 1;
84   }
85   (*output) = result;
86   bpf_call_timestamp_buf_submit(output);
87   return 0;
88 }
89 
90 DEFINE_BPF_PROG("uprobe/call_timestamp_2", AID_UPROBESTATS, AID_UPROBESTATS,
91                 BPF_KPROBE2)
92 () {
93   struct CallTimestamp result;
94   result.event = 2;
95   result.timestampNs = bpf_ktime_get_ns();
96   struct CallTimestamp *output = bpf_call_timestamp_buf_reserve();
97   if (output == NULL) {
98     return 1;
99   }
100   (*output) = result;
101   bpf_call_timestamp_buf_submit(output);
102   return 0;
103 }
104 
105 DEFINE_BPF_PROG("uprobe/call_timestamp_3", AID_UPROBESTATS, AID_UPROBESTATS,
106                 BPF_KPROBE3)
107 () {
108   struct CallTimestamp result;
109   result.event = 3;
110   result.timestampNs = bpf_ktime_get_ns();
111   struct CallTimestamp *output = bpf_call_timestamp_buf_reserve();
112   if (output == NULL) {
113     return 1;
114   }
115   (*output) = result;
116   bpf_call_timestamp_buf_submit(output);
117   return 0;
118 }
119 
120 DEFINE_BPF_PROG("uprobe/call_timestamp_4", AID_UPROBESTATS, AID_UPROBESTATS,
121                 BPF_KPROBE4)
122 () {
123   struct CallTimestamp result;
124   result.event = 4;
125   result.timestampNs = bpf_ktime_get_ns();
126   struct CallTimestamp *output = bpf_call_timestamp_buf_reserve();
127   if (output == NULL) {
128     return 1;
129   }
130   (*output) = result;
131   bpf_call_timestamp_buf_submit(output);
132   return 0;
133 }
134 
135 DEFINE_BPF_PROG("uprobe/call_timestamp_5", AID_UPROBESTATS, AID_UPROBESTATS,
136                 BPF_KPROBE5)
137 () {
138   struct CallTimestamp result;
139   result.event = 5;
140   result.timestampNs = bpf_ktime_get_ns();
141   struct CallTimestamp *output = bpf_call_timestamp_buf_reserve();
142   if (output == NULL) {
143     return 1;
144   }
145   (*output) = result;
146   bpf_call_timestamp_buf_submit(output);
147   return 0;
148 }
149 
150 LICENSE("GPL");
151