Merge tag 'v3.14.25' into backport/v3.14.24-ltsi-rc1+v3.14.25/snapshot-merge.wip
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / staging / ktap / userspace / util.c
1 /*
2  * util.c
3  *
4  * This file is part of ktap by Jovi Zhangwei.
5  *
6  * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
7  *
8  * Copyright (C) 1994-2013 Lua.org, PUC-Rio.
9  *  - The part of code in this file is copied from lua initially.
10  *  - lua's MIT license is compatible with GPL.
11  *
12  * ktap is free software; you can redistribute it and/or modify it
13  * under the terms and conditions of the GNU General Public License,
14  * version 2, as published by the Free Software Foundation.
15  *
16  * ktap is distributed in the hope it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  *
21  * You should have received a copy of the GNU General Public License along with
22  * this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <math.h>
31 #include "../include/ktap_types.h"
32 #include "../include/ktap_opcodes.h"
33 #include "ktapc.h"
34
35 /*
36  * converts an integer to a "floating point byte", represented as
37  * (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
38  * eeeee != 0 and (xxx) otherwise.
39  */
40 int ktapc_int2fb(unsigned int x)
41 {
42         int e = 0;  /* exponent */
43
44         if (x < 8)
45                 return x;
46         while (x >= 0x10) {
47                 x = (x+1) >> 1;
48                 e++;
49         }
50         return ((e+1) << 3) | ((int)x - 8);
51 }
52
53 /* converts back */
54 int ktapc_fb2int(int x)
55 {
56         int e = (x >> 3) & 0x1f;
57
58         if (e == 0)
59                 return x;
60         else
61                 return ((x & 7) + 8) << (e - 1);
62 }
63
64 int ktapc_ceillog2(unsigned int x)
65 {
66         static const u8 log_2[256] = {
67         0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
68         6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
69         7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
70         7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
71         8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
72         8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
73         8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
74         8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
75         };
76         int l = 0;
77
78         x--;
79         while (x >= 256) {
80                 l += 8;
81                 x >>= 8;
82         }
83         return l + log_2[x];
84 }
85
86 ktap_number ktapc_arith(int op, ktap_number v1, ktap_number v2)
87 {
88         switch (op) {
89         case KTAP_OPADD: return NUMADD(v1, v2);
90         case KTAP_OPSUB: return NUMSUB(v1, v2);
91         case KTAP_OPMUL: return NUMMUL(v1, v2);
92         case KTAP_OPDIV: return NUMDIV(v1, v2);
93         case KTAP_OPMOD: return NUMMOD(v1, v2);
94         //case KTAP_OPPOW: return NUMPOW(v1, v2);
95         case KTAP_OPUNM: return NUMUNM(v1);
96         default: ktap_assert(0); return 0;
97         }
98 }
99
100 int ktapc_hexavalue(int c)
101 {
102         if (isdigit(c))
103                 return c - '0';
104         else
105                 return tolower(c) - 'a' + 10;
106 }
107
108 int ktapc_str2d(const char *s, size_t len, ktap_number *result)
109 {
110         char *endptr;
111
112         if (strpbrk(s, "nN"))  /* reject 'inf' and 'nan' */
113                 return 0;
114         else
115                 *result = (long)strtoul(s, &endptr, 0);
116
117         if (endptr == s)
118                 return 0;  /* nothing recognized */
119         while (isspace((unsigned char)(*endptr)))
120                 endptr++;
121         return (endptr == s + len);  /* OK if no trailing characters */
122 }
123
124 /* number of chars of a literal string without the ending \0 */
125 #define LL(x)   (sizeof(x)/sizeof(char) - 1)
126
127 #define RETS    "..."
128 #define PRE     "[string \""
129 #define POS     "\"]"
130
131 #define addstr(a,b,l)   ( memcpy(a,b,(l) * sizeof(char)), a += (l) )
132
133 void ktapc_chunkid(char *out, const char *source, size_t bufflen)
134 {
135         size_t l = strlen(source);
136
137         if (*source == '=') {  /* 'literal' source */
138                 if (l <= bufflen)  /* small enough? */
139                         memcpy(out, source + 1, l * sizeof(char));
140                 else {  /* truncate it */
141                         addstr(out, source + 1, bufflen - 1);
142                         *out = '\0';
143                 }
144         } else if (*source == '@') {  /* file name */
145                 if (l <= bufflen)  /* small enough? */
146                         memcpy(out, source + 1, l * sizeof(char));
147                 else {  /* add '...' before rest of name */
148                         addstr(out, RETS, LL(RETS));
149                         bufflen -= LL(RETS);
150                         memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char));
151                 }
152         } else {  /* string; format as [string "source"] */
153                 const char *nl = strchr(source, '\n');  /* find first new line (if any) */
154                 addstr(out, PRE, LL(PRE));  /* add prefix */
155                 bufflen -= LL(PRE RETS POS) + 1;  /* save space for prefix+suffix+'\0' */
156                 if (l < bufflen && nl == NULL) {  /* small one-line source? */
157                         addstr(out, source, l);  /* keep it */
158                 } else {
159                         if (nl != NULL)
160                                 l = nl - source;  /* stop at first newline */
161                         if (l > bufflen)
162                                 l = bufflen;
163                         addstr(out, source, l);
164                         addstr(out, RETS, LL(RETS));
165                 }
166                 memcpy(out, POS, (LL(POS) + 1) * sizeof(char));
167         }
168 }
169
170
171 /*
172  * strglobmatch is copyed from perf(linux/tools/perf/util/string.c)
173  */
174
175 /* Character class matching */
176 static bool __match_charclass(const char *pat, char c, const char **npat)
177 {
178         bool complement = false, ret = true;
179
180         if (*pat == '!') {
181                 complement = true;
182                 pat++;
183         }
184         if (*pat++ == c)        /* First character is special */
185                 goto end;
186
187         while (*pat && *pat != ']') {   /* Matching */
188                 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
189                         if (*(pat - 1) <= c && c <= *(pat + 1))
190                                 goto end;
191                         if (*(pat - 1) > *(pat + 1))
192                                 goto error;
193                         pat += 2;
194                 } else if (*pat++ == c)
195                         goto end;
196         }
197         if (!*pat)
198                 goto error;
199         ret = false;
200
201 end:
202         while (*pat && *pat != ']')     /* Searching closing */
203                 pat++;
204         if (!*pat)
205                 goto error;
206         *npat = pat + 1;
207         return complement ? !ret : ret;
208
209 error:
210         return false;
211 }
212
213 /* Glob/lazy pattern matching */
214 static bool __match_glob(const char *str, const char *pat, bool ignore_space)
215 {
216         while (*str && *pat && *pat != '*') {
217                 if (ignore_space) {
218                         /* Ignore spaces for lazy matching */
219                         if (isspace(*str)) {
220                                 str++;
221                                 continue;
222                         }
223                         if (isspace(*pat)) {
224                                 pat++;
225                                 continue;
226                         }
227                 }
228                 if (*pat == '?') {      /* Matches any single character */
229                         str++;
230                         pat++;
231                         continue;
232                 } else if (*pat == '[') /* Character classes/Ranges */
233                         if (__match_charclass(pat + 1, *str, &pat)) {
234                                 str++;
235                                 continue;
236                         } else
237                                 return false;
238                 else if (*pat == '\\') /* Escaped char match as normal char */
239                         pat++;
240                 if (*str++ != *pat++)
241                         return false;
242         }
243         /* Check wild card */
244         if (*pat == '*') {
245                 while (*pat == '*')
246                         pat++;
247                 if (!*pat)      /* Tail wild card matches all */
248                         return true;
249                 while (*str)
250                         if (__match_glob(str++, pat, ignore_space))
251                                 return true;
252         }
253         return !*str && !*pat;
254 }
255
256 /**
257  * strglobmatch - glob expression pattern matching
258  * @str: the target string to match
259  * @pat: the pattern string to match
260  *
261  * This returns true if the @str matches @pat. @pat can includes wildcards
262  * ('*','?') and character classes ([CHARS], complementation and ranges are
263  * also supported). Also, this supports escape character ('\') to use special
264  * characters as normal character.
265  *
266  * Note: if @pat syntax is broken, this always returns false.
267  */
268 bool strglobmatch(const char *str, const char *pat)
269 {
270         return __match_glob(str, pat, false);
271 }
272
273 #define handle_error(str) do { perror(str); exit(-1); } while(0)
274
275 #define KALLSYMS_PATH "/proc/kallsyms"
276 /*
277  * read kernel symbol from /proc/kallsyms
278  */
279 int kallsyms_parse(void *arg,
280                    int(*process_symbol)(void *arg, const char *name,
281                    char type, unsigned long start))
282 {
283         int ret = 0;
284         FILE *file;
285         char *line = NULL;
286
287         file = fopen(KALLSYMS_PATH, "r");
288         if (file == NULL)
289                 handle_error("open " KALLSYMS_PATH " failed");
290
291         while (!feof(file)) {
292                 char *symbol_addr, *symbol_name;
293                 char symbol_type;
294                 unsigned long start;
295                 int line_len;
296                 size_t n;
297
298                 line_len = getline(&line, &n, file);
299                 if (line_len < 0 || !line)
300                         break;
301
302                 line[--line_len] = '\0'; /* \n */
303
304                 symbol_addr = strtok(line, " \t");
305                 start = strtoul(symbol_addr, NULL, 16);
306
307                 symbol_type = *strtok(NULL, " \t");
308                 symbol_name = strtok(NULL, " \t");
309
310                 ret = process_symbol(arg, symbol_name, symbol_type, start);
311                 if (ret)
312                         break;
313         }
314
315         free(line);
316         fclose(file);
317
318         return ret;
319 }
320
321 struct ksym_addr_t {
322         const char *name;
323         unsigned long addr;
324 };
325
326 static int symbol_cmp(void *arg, const char *name, char type,
327                       unsigned long start)
328 {
329         struct ksym_addr_t *base = arg;
330
331         if (strcmp(base->name, name) == 0) {
332                 base->addr = start;
333                 return 1;
334         }
335
336         return 0;
337 }
338
339 unsigned long find_kernel_symbol(const char *symbol)
340 {
341         int ret;
342         struct ksym_addr_t arg = {
343                 .name = symbol,
344                 .addr = 0
345         };
346
347         ret = kallsyms_parse(&arg, symbol_cmp);
348         if (ret < 0 || arg.addr == 0) {
349                 fprintf(stderr, "cannot read kernel symbol \"%s\" in %s\n",
350                         symbol, KALLSYMS_PATH);
351                 exit(EXIT_FAILURE);
352         }
353
354         return arg.addr;
355 }
356
357
358 #define AVAILABLE_EVENTS_PATH "/sys/kernel/debug/tracing/available_events"
359
360 void list_available_events(const char *match)
361 {
362         FILE *file;
363         char *line = NULL;
364
365         file = fopen(AVAILABLE_EVENTS_PATH, "r");
366         if (file == NULL)
367                 handle_error("open " AVAILABLE_EVENTS_PATH " failed");
368
369         while (!feof(file)) {
370                 size_t n;
371
372                 getline(&line, &n, file);
373
374                 if (!match || strglobmatch(line, match))
375                         printf("%s", line);
376         }
377
378         free(line);
379         fclose(file);
380 }
381