Commit | Line | Data |
---|---|---|
b26e2ae7 | 1 | /* Emulation of eBPF helpers. |
88b9d363 | 2 | Copyright (C) 2020-2022 Free Software Foundation, Inc. |
b26e2ae7 JM |
3 | |
4 | This file is part of GDB, the GNU debugger. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 3 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | /* BPF programs rely on the existence of several helper functions, | |
20 | which are provided by the kernel. This simulator provides an | |
21 | implementation of the helpers, which can be customized by the | |
22 | user. */ | |
23 | ||
6df01ab8 MF |
24 | /* This must come before any other includes. */ |
25 | #include "defs.h" | |
26 | ||
b26e2ae7 JM |
27 | #define WANT_CPU_BPFBF |
28 | #define WANT_CPU bpfbf | |
29 | ||
30 | #include "sim-main.h" | |
31 | #include "cgen-mem.h" | |
32 | #include "cgen-ops.h" | |
33 | #include "cpu.h" | |
34 | ||
76f11310 MF |
35 | #include "bpf-helpers.h" |
36 | ||
b26e2ae7 JM |
37 | /* bpf_trace_printk is a printk-like facility for debugging. |
38 | ||
39 | In the kernel, it appends a line to the Linux's tracing debugging | |
40 | interface. | |
41 | ||
42 | In this simulator, it uses the simulator's tracing interface | |
43 | instead. | |
44 | ||
45 | The format tags recognized by this helper are: | |
46 | %d, %i, %u, %x, %ld, %li, %lu, %lx, %lld, %lli, %llu, %llx, | |
47 | %p, %s | |
48 | ||
49 | A maximum of three tags are supported. | |
50 | ||
51 | This helper returns the number of bytes written, or a negative | |
52 | value in case of failure. */ | |
53 | ||
54 | int | |
55 | bpf_trace_printk (SIM_CPU *current_cpu) | |
56 | { | |
57 | va_list ap; | |
58 | SIM_DESC sd = CPU_STATE (current_cpu); | |
59 | ||
60 | DI fmt_address; | |
61 | uint32_t size, tags_processed; | |
62 | size_t i, bytes_written = 0; | |
63 | ||
64 | /* The first argument is the format string, which is passed as a | |
65 | pointer in %r1. */ | |
66 | fmt_address = GET_H_GPR (1); | |
67 | ||
68 | /* The second argument is the length of the format string, as an | |
69 | unsigned 32-bit number in %r2. */ | |
70 | size = GET_H_GPR (2); | |
71 | ||
72 | /* Read the format string from the memory pointed by %r2, printing | |
73 | out the stuff as we go. There is a maximum of three format tags | |
74 | supported, which are read from %r3, %r4 and %r5 respectively. */ | |
75 | for (i = 0, tags_processed = 0; i < size;) | |
76 | { | |
cc9c19b0 | 77 | UDI value; |
b26e2ae7 JM |
78 | QI c = GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu), |
79 | fmt_address + i); | |
80 | ||
81 | switch (c) | |
82 | { | |
83 | case '%': | |
84 | /* Check we are not exceeding the limit of three format | |
85 | tags. */ | |
86 | if (tags_processed > 2) | |
87 | return -1; /* XXX look for kernel error code. */ | |
88 | ||
89 | /* Depending on the kind of tag, extract the value from the | |
90 | proper argument. */ | |
91 | if (i++ >= size) | |
92 | return -1; /* XXX look for kernel error code. */ | |
93 | ||
cc9c19b0 | 94 | value = GET_H_GPR (3 + tags_processed); |
b26e2ae7 JM |
95 | |
96 | switch ((GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu), | |
97 | fmt_address + i))) | |
98 | { | |
99 | case 'd': | |
44e88cd6 | 100 | trace_printf (sd, current_cpu, "%d", (int) value); |
b26e2ae7 JM |
101 | break; |
102 | case 'i': | |
44e88cd6 | 103 | trace_printf (sd, current_cpu, "%i", (int) value); |
b26e2ae7 JM |
104 | break; |
105 | case 'u': | |
44e88cd6 | 106 | trace_printf (sd, current_cpu, "%u", (unsigned int) value); |
b26e2ae7 JM |
107 | break; |
108 | case 'x': | |
44e88cd6 | 109 | trace_printf (sd, current_cpu, "%x", (unsigned int) value); |
b26e2ae7 JM |
110 | break; |
111 | case 'l': | |
112 | { | |
113 | if (i++ >= size) | |
114 | return -1; | |
115 | switch (GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu), | |
116 | fmt_address + i)) | |
117 | { | |
118 | case 'd': | |
44e88cd6 | 119 | trace_printf (sd, current_cpu, "%ld", (long) value); |
b26e2ae7 JM |
120 | break; |
121 | case 'i': | |
44e88cd6 | 122 | trace_printf (sd, current_cpu, "%li", (long) value); |
b26e2ae7 JM |
123 | break; |
124 | case 'u': | |
44e88cd6 | 125 | trace_printf (sd, current_cpu, "%lu", (unsigned long) value); |
b26e2ae7 JM |
126 | break; |
127 | case 'x': | |
44e88cd6 | 128 | trace_printf (sd, current_cpu, "%lx", (unsigned long) value); |
b26e2ae7 JM |
129 | break; |
130 | case 'l': | |
131 | { | |
132 | if (i++ >= size) | |
133 | return -1; | |
134 | switch (GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu), | |
135 | fmt_address + i)) { | |
136 | case 'd': | |
44e88cd6 | 137 | trace_printf (sd, current_cpu, "%lld", (long long) value); |
b26e2ae7 JM |
138 | break; |
139 | case 'i': | |
44e88cd6 | 140 | trace_printf (sd, current_cpu, "%lli", (long long) value); |
b26e2ae7 JM |
141 | break; |
142 | case 'u': | |
44e88cd6 | 143 | trace_printf (sd, current_cpu, "%llu", (unsigned long long) value); |
b26e2ae7 JM |
144 | break; |
145 | case 'x': | |
44e88cd6 | 146 | trace_printf (sd, current_cpu, "%llx", (unsigned long long) value); |
b26e2ae7 JM |
147 | break; |
148 | default: | |
149 | assert (0); | |
150 | break; | |
151 | } | |
152 | break; | |
153 | } | |
154 | default: | |
155 | assert (0); | |
156 | break; | |
157 | } | |
158 | break; | |
159 | } | |
160 | default: | |
161 | /* XXX completeme */ | |
162 | assert (0); | |
163 | break; | |
164 | } | |
165 | ||
166 | tags_processed++; | |
167 | i++; | |
168 | break; | |
169 | case '\0': | |
170 | i = size; | |
171 | break; | |
172 | default: | |
173 | trace_printf (sd, current_cpu, "%c", c); | |
174 | bytes_written++; | |
175 | i++; | |
176 | break; | |
177 | } | |
178 | } | |
179 | ||
180 | return bytes_written; | |
181 | } |