1241675Suqs/* Emulation of eBPF helpers. 2241675Suqs Copyright (C) 2020 Free Software Foundation, Inc. 3241675Suqs 4241675Suqs This file is part of GDB, the GNU debugger. 5241675Suqs 6241675Suqs This program is free software; you can redistribute it and/or modify 7241675Suqs it under the terms of the GNU General Public License as published by 8241675Suqs the Free Software Foundation; either version 3 of the License, or 9241675Suqs (at your option) any later version. 10241675Suqs 11241675Suqs This program is distributed in the hope that it will be useful, 12241675Suqs but WITHOUT ANY WARRANTY; without even the implied warranty of 13241675Suqs MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14241675Suqs GNU General Public License for more details. 15241675Suqs 16241675Suqs You should have received a copy of the GNU General Public License 17241675Suqs along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18241675Suqs 19241675Suqs/* BPF programs rely on the existence of several helper functions, 20241675Suqs which are provided by the kernel. This simulator provides an 21241675Suqs implementation of the helpers, which can be customized by the 22241675Suqs user. */ 23241675Suqs 24241675Suqs#define WANT_CPU_BPFBF 25241675Suqs#define WANT_CPU bpfbf 26241675Suqs 27241675Suqs#include "sim-main.h" 28241675Suqs#include "cgen-mem.h" 29241675Suqs#include "cgen-ops.h" 30241675Suqs#include "cpu.h" 31241675Suqs 32241675Suqs/* bpf_trace_printk is a printk-like facility for debugging. 33241675Suqs 34241675Suqs In the kernel, it appends a line to the Linux's tracing debugging 35241675Suqs interface. 36241675Suqs 37241675Suqs In this simulator, it uses the simulator's tracing interface 38241675Suqs instead. 39241675Suqs 40241675Suqs The format tags recognized by this helper are: 41241675Suqs %d, %i, %u, %x, %ld, %li, %lu, %lx, %lld, %lli, %llu, %llx, 42241675Suqs %p, %s 43241675Suqs 44241675Suqs A maximum of three tags are supported. 45241675Suqs 46241675Suqs This helper returns the number of bytes written, or a negative 47241675Suqs value in case of failure. */ 48241675Suqs 49241675Suqsint 50241675Suqsbpf_trace_printk (SIM_CPU *current_cpu) 51241675Suqs{ 52241675Suqs va_list ap; 53241675Suqs SIM_DESC sd = CPU_STATE (current_cpu); 54241675Suqs 55241675Suqs DI fmt_address; 56241675Suqs uint32_t size, tags_processed; 57241675Suqs size_t i, bytes_written = 0; 58241675Suqs 59241675Suqs /* The first argument is the format string, which is passed as a 60241675Suqs pointer in %r1. */ 61241675Suqs fmt_address = GET_H_GPR (1); 62241675Suqs 63241675Suqs /* The second argument is the length of the format string, as an 64241675Suqs unsigned 32-bit number in %r2. */ 65241675Suqs size = GET_H_GPR (2); 66241675Suqs 67241675Suqs /* Read the format string from the memory pointed by %r2, printing 68241675Suqs out the stuff as we go. There is a maximum of three format tags 69241675Suqs supported, which are read from %r3, %r4 and %r5 respectively. */ 70241675Suqs for (i = 0, tags_processed = 0; i < size;) 71241675Suqs { 72241675Suqs QI c = GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu), 73241675Suqs fmt_address + i); 74241675Suqs 75241675Suqs switch (c) 76241675Suqs { 77241675Suqs case '%': 78241675Suqs /* Check we are not exceeding the limit of three format 79241675Suqs tags. */ 80241675Suqs if (tags_processed > 2) 81241675Suqs return -1; /* XXX look for kernel error code. */ 82241675Suqs 83241675Suqs /* Depending on the kind of tag, extract the value from the 84241675Suqs proper argument. */ 85241675Suqs if (i++ >= size) 86241675Suqs return -1; /* XXX look for kernel error code. */ 87241675Suqs 88241675Suqs UDI value = GET_H_GPR (3 + tags_processed); 89241675Suqs 90241675Suqs switch ((GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu), 91241675Suqs fmt_address + i))) 92241675Suqs { 93241675Suqs case 'd': 94241675Suqs trace_printf (sd, current_cpu, "%d", value); 95241675Suqs break; 96241675Suqs case 'i': 97241675Suqs trace_printf (sd, current_cpu, "%i", value); 98241675Suqs break; 99241675Suqs case 'u': 100241675Suqs trace_printf (sd, current_cpu, "%u", value); 101241675Suqs break; 102241675Suqs case 'x': 103241675Suqs trace_printf (sd, current_cpu, "%x", value); 104241675Suqs break; 105241675Suqs case 'l': 106241675Suqs { 107241675Suqs if (i++ >= size) 108241675Suqs return -1; 109241675Suqs switch (GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu), 110241675Suqs fmt_address + i)) 111241675Suqs { 112 case 'd': 113 trace_printf (sd, current_cpu, "%ld", value); 114 break; 115 case 'i': 116 trace_printf (sd, current_cpu, "%li", value); 117 break; 118 case 'u': 119 trace_printf (sd, current_cpu, "%lu", value); 120 break; 121 case 'x': 122 trace_printf (sd, current_cpu, "%lx", value); 123 break; 124 case 'l': 125 { 126 if (i++ >= size) 127 return -1; 128 switch (GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu), 129 fmt_address + i)) { 130 case 'd': 131 trace_printf (sd, current_cpu, "%lld", value); 132 break; 133 case 'i': 134 trace_printf (sd, current_cpu, "%lli", value); 135 break; 136 case 'u': 137 trace_printf (sd, current_cpu, "%llu", value); 138 break; 139 case 'x': 140 trace_printf (sd, current_cpu, "%llx", value); 141 break; 142 default: 143 assert (0); 144 break; 145 } 146 break; 147 } 148 default: 149 assert (0); 150 break; 151 } 152 break; 153 } 154 default: 155 /* XXX completeme */ 156 assert (0); 157 break; 158 } 159 160 tags_processed++; 161 i++; 162 break; 163 case '\0': 164 i = size; 165 break; 166 default: 167 trace_printf (sd, current_cpu, "%c", c); 168 bytes_written++; 169 i++; 170 break; 171 } 172 } 173 174 return bytes_written; 175} 176