improve rule checker function in xevlog_analyze
[adaptation/xorg/driver/xserver-xorg-module-xdbg.git] / common / xdbg_evlog.c
1 /**************************************************************************
2
3 xdbg
4
5 Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
6
7 Contact: Boram Park <boram1288.park@samsung.com>
8          Sangjin LEE <lsj119@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <sys/types.h>
36 #include <sys/fcntl.h>
37 #include <unistd.h>
38 #include <stdarg.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <time.h>
42 #include <X11/Xlib.h>
43
44 #include "xdbg_types.h"
45 #include "xdbg_evlog.h"
46 #include "bool_exp_rule_checker.h"
47 #include <X11/Xlibint.h>
48
49 #ifndef XDBG_CLIENT
50 #include "resource.h"
51 #include "region.h"
52 #include "dix.h"
53 #endif
54
55 static char *evt_type[] = { "Event", "Request", "Reply", "Flush" };
56 static char *evt_dir[]  = { "<====", "---->",   "<----", "*****" };
57
58 static RULE_CHECKER rc = NULL;
59
60 static void
61 _mergeArgs (char * target, int argc, const char ** argv)
62 {
63     int i;
64     int len;
65
66     for (i=0; i<argc; i++)
67     {
68         len = sprintf (target, "%s", argv[i]);
69         target += len;
70
71         if (i != argc - 1)
72             *(target++) = ' ';
73     }
74 }
75
76 static int
77 _strcasecmp(const char *str1, const char *str2)
78 {
79     const u_char *us1 = (const u_char *) str1, *us2 = (const u_char *) str2;
80
81     while (tolower(*us1) == tolower(*us2)) {
82         if (*us1++ == '\0')
83             return 0;
84         us2++;
85     }
86
87     return (tolower(*us1) - tolower(*us2));
88 }
89
90 char*
91 xDbgEvlogGetCmd (char *path)
92 {
93     char *p;
94     if (!path)
95         return NULL;
96     p = strrchr (path, '/');
97     return (p)?p+1:path;
98 }
99
100 Bool
101 xDbgEvlogRuleSet (const int argc, const char **argv, char *reply, int *len)
102 {
103     const char * command;
104
105     if (rc == NULL)
106         rc = rulechecker_init();
107
108     if (argc == 0)
109     {
110         rulechecker_print_rule (rc, reply);
111         return TRUE;
112     }
113
114     command = argv[0];
115
116     if (!_strcasecmp (command, "add"))
117     {
118         POLICY_TYPE policy_type;
119         RC_RESULT_TYPE result;
120         const char * policy = argv[1];
121         char rule[8192];
122         int i;
123
124         if (argc < 3)
125         {
126             REPLY ("Error : Too few arguments.\n");
127             return FALSE;
128         }
129
130         if (!_strcasecmp (policy, "ALLOW"))
131             policy_type = ALLOW;
132         else if (!_strcasecmp (policy, "DENY"))
133             policy_type = DENY;
134         else
135         {
136             REPLY ("Error : Unknown policy : [%s].\n          Policy should be ALLOW or DENY.\n", policy);
137             return FALSE;
138         }
139
140         _mergeArgs (rule, argc - 2, &(argv[2]));
141
142         for (i = 0 ; i < strlen(rule) ; i++)
143             if(rule[i] == '\"' || rule[i] == '\'')
144                 rule[i] = ' ';
145
146         result = rulechecker_add_rule (rc, policy_type, rule);
147         if (result == RC_ERR_TOO_MANY_RULES)
148         {
149             REPLY ("Error : Too many rules were added.\n");
150             return FALSE;
151         }
152         else if (result == RC_ERR_PARSE_ERROR)
153         {
154             REPLY ("Error : An error occured during parsing the rule [%s]\n", rule);
155             return FALSE;
156         }
157
158         REPLY ("The rule was successfully added.\n\n");
159         rulechecker_print_rule (rc, reply);
160         return TRUE;
161     }
162     else if (!_strcasecmp (command, "remove"))
163     {
164         const char * remove_idx;
165         int i;
166
167         if (argc < 2)
168         {
169             REPLY ("Error : Too few arguments.\n");
170             return FALSE;
171         }
172
173         for (i=0; i<argc - 1; i++)
174         {
175             remove_idx = argv[i+1];
176
177             if (!_strcasecmp (remove_idx, "all"))
178             {
179                 rulechecker_destroy (rc);
180                 rc = rulechecker_init();
181                 REPLY ("Every rules were successfully removed.\n");
182             }
183             else
184             {
185                 int index = atoi (remove_idx);
186                 if (isdigit (*remove_idx) && rulechecker_remove_rule (rc, index) == 0)
187                     REPLY ("The rule [%d] was successfully removed.\n", index);
188                 else
189                     REPLY ("Rule remove fail : No such rule [%s].\n", remove_idx);
190             }
191         }
192         rulechecker_print_rule (rc, reply);
193         return TRUE;
194     }
195     else if (!_strcasecmp (command, "print"))
196     {
197         rulechecker_print_rule (rc, reply);
198         return TRUE;
199     }
200     else if (!_strcasecmp (command, "help"))
201     {
202         REPLY ("%s", rulechecker_print_usage());
203         return TRUE;
204     }
205
206     REPLY ("%s\nUnknown command : [%s].\n\n", rulechecker_print_usage(), command);
207
208     return TRUE;
209 }
210
211 Bool
212 xDbgEvlogRuleValidate (EvlogInfo *evinfo)
213 {
214     const char *evlog_name = "";
215     char *cmd = "";
216
217     if (rc == NULL)
218         rc = rulechecker_init ();
219
220     if (!rc)
221     {
222         XDBG_LOG ("failed: create rulechecker\n");
223         return FALSE;
224     }
225
226     cmd = xDbgEvlogGetCmd (evinfo->client.command);
227
228     if (evinfo->type == REQUEST)
229         evlog_name = evinfo->req.name;
230     else if (evinfo->type == EVENT)
231         evlog_name = evinfo->evt.name;
232
233     return rulechecker_validate_rule (rc,
234                                       evinfo->type,
235                                       evinfo->req.id,
236                                       evlog_name,
237                                       evinfo->client.pid,
238                                       cmd);
239 }
240
241
242 ExtensionInfo Evlog_extensions[] = {
243     {xDbgEvlogCompositeGetBase, 0, 0, 0, NULL},
244     {xDbgEvlogDamageGetBase, 0, 0, 0, NULL},
245     {xDbgEvlogDri2GetBase, 0, 0, 0, NULL},
246     {xDbgEvlogGestureGetBase, 0, 0, 0, NULL},
247     {xDbgEvlogRandrGetBase, 0, 0, 0, NULL},
248     {xDbgEvlogXextDpmsGetBase, 0, 0, 0, NULL},
249     {xDbgEvlogXextShmGetBase, 0, 0, 0, NULL},
250     {xDbgEvlogXextSyncGetBase, 0, 0, 0, NULL},
251     {xDbgEvlogXextXtestGetBase, 0, 0, 0, NULL},
252     {xDbgEvlogXextXtestExt1GetBase, 0, 0, 0, NULL},
253     {xDbgEvlogXvGetBase, 0, 0, 0, NULL}
254 };
255 ExtensionInfo* Sorted_Evlog_extensions;
256 int Extensions_size = 0;
257
258 static void
259 _ExtensionsSwap(ExtensionInfo* first, ExtensionInfo* second)
260 {
261     ExtensionInfo temp;
262
263     temp = *first ;
264     *first = *second ;
265     *second = temp ;
266 }
267
268 static Bool
269 _SortEvlogExtensions ()
270 {
271     int i,j;
272     int swap;
273
274     Sorted_Evlog_extensions = (ExtensionInfo*)malloc(sizeof(Evlog_extensions));
275     RETURN_VAL_IF_FAIL (Sorted_Evlog_extensions != NULL, FALSE);
276
277     memcpy(Sorted_Evlog_extensions, Evlog_extensions, sizeof(Evlog_extensions));
278
279     for (i = 0 ; i < Extensions_size - 1 ; i++)
280     {
281         swap = 0;
282         for (j = 1 ; j < Extensions_size - i ; j++)
283         {
284             if(Sorted_Evlog_extensions[j-1].evt_base > Sorted_Evlog_extensions[j].evt_base)
285             {
286                 _ExtensionsSwap(&Sorted_Evlog_extensions[j-1], &Sorted_Evlog_extensions[j]);
287                 swap = 1;
288             }
289         }
290         if (!swap) break;
291     }
292
293     return TRUE;
294 }
295
296
297 Bool
298 xDbgEvlogGetExtensionEntry ()
299 {
300     static int init = 0;
301     static Bool success = FALSE;
302     int i;
303
304     if (init)
305         return success;
306
307     init = 1;
308     Extensions_size = sizeof(Evlog_extensions) / sizeof (ExtensionInfo);
309
310     for (i = 0 ; i < Extensions_size ; i++)
311     {
312         Evlog_extensions[i].get_base_func (Evlog_extensions + i);
313     }
314
315     if(!_SortEvlogExtensions ())
316         return FALSE;
317
318
319     success = TRUE;
320
321     return success;
322 }
323
324
325 void
326 xDbgEvlogFillLog (EvlogInfo *evinfo, Bool on, char *reply, int *len)
327 {
328     static CARD32 prev;
329
330     RETURN_IF_FAIL (evinfo->type >= 0 && (sizeof (evt_dir) / sizeof (char*)));
331     RETURN_IF_FAIL (evinfo->type >= 0 && (sizeof (evt_type) / sizeof (char*)));
332
333     REPLY ("[%10.3f][%5ld] %22s(%2d:%5d) %s %7s ",
334                 evinfo->time / 1000.0,
335                 evinfo->time - prev,
336                 xDbgEvlogGetCmd (evinfo->client.command),
337                 evinfo->client.index,
338                 evinfo->client.pid,
339                 evt_dir[evinfo->type],
340                 evt_type[evinfo->type]);
341
342     if (evinfo->type == REQUEST)
343     {
344         REPLY ("(");
345         reply = xDbgEvlogReqeust (evinfo, on, reply, len);
346         REPLY (")");
347     }
348     else if (evinfo->type == EVENT)
349     {
350         evinfo->evt.size = sizeof (xEvent);
351         REPLY ("(");
352         reply = xDbgEvlogEvent (evinfo, on, reply, len);
353         REPLY (")");
354     }
355     else
356     {
357         const char *evlog_name = "";
358         if (evinfo->type == REQUEST)
359             evlog_name = evinfo->req.name;
360         else if (evinfo->type == EVENT)
361             evlog_name = evinfo->evt.name;
362         REPLY ("(%s)", evlog_name);
363     }
364
365     REPLY ("\n");
366
367     prev = evinfo->time;
368 }
369
370
371 void xDbgDistroyAtomList (EvlogInfo *evinfo)
372 {
373     EvlogAtomTable *cur, *next;
374
375     if (!evinfo->evatom.init)
376         return;
377
378     xorg_list_for_each_entry_safe(cur, next, &evinfo->evatom.list, link)
379     {
380         xorg_list_del(&cur->link);
381         free (cur);
382         cur = NULL;
383     }
384     evinfo->evatom.init = 0;
385     evinfo->evatom.size = 0;
386 }
387
388 void xDbgDistroyRegionList (EvlogInfo *evinfo)
389 {
390     EvlogRegionTable *cur, *next;
391
392     if (!evinfo->evregion.init)
393         return;
394
395     xorg_list_for_each_entry_safe(cur, next, &evinfo->evregion.list, link)
396     {
397         xorg_list_del(&cur->link);
398         free (cur);
399         cur = NULL;
400     }
401     evinfo->evregion.init = 0;
402     evinfo->evregion.size = 0;
403 }
404
405 char* xDbgGetAtom(Atom atom, EvlogInfo *evinfo, char *reply, int *len)
406 {
407     EvlogAtomTable *table;
408 #ifndef XDBG_CLIENT
409     table = malloc (sizeof(EvlogAtomTable));
410     if (!table)
411         return reply;
412
413     evinfo->mask |= EVLOG_MASK_ATOM;
414     table->xid = atom;
415
416     if (!evinfo->evatom.init)
417     {
418         xorg_list_init(&evinfo->evatom.list);
419         evinfo->evatom.init = 1;
420     }
421
422     if (NameForAtom(atom))
423         snprintf (table->buf, XDBG_BUF_SIZE, "%s", (char*)NameForAtom(atom));
424     else
425         snprintf (table->buf, XDBG_BUF_SIZE, "0x%lx", atom);
426
427     xorg_list_add(&table->link, &evinfo->evatom.list);
428     evinfo->evatom.size++;
429 #endif
430     xorg_list_for_each_entry(table, &evinfo->evatom.list, link)
431         if(table->xid == atom)
432         {
433             REPLY ("(%s)", table->buf);
434             break;
435         }
436
437     return reply;
438 }
439
440 char* xDbgGetRegion(XserverRegion region, EvlogInfo *evinfo, char *reply, int *len)
441 {
442     EvlogRegionTable *table;
443 #ifndef XDBG_CLIENT
444     extern _X_EXPORT RESTYPE RegionResType;
445     RegionPtr pRegion;
446     BoxPtr rects;
447     int nrect, i;
448     int s;
449     int err = dixLookupResourceByType((pointer *) &pRegion, region,
450                                        RegionResType, (ClientPtr)evinfo->client.pClient,
451                                        DixReadAccess);
452
453     evinfo->mask |= EVLOG_MASK_REGION;
454
455     if (!evinfo->evregion.init)
456     {
457         xorg_list_init(&evinfo->evregion.list);
458         evinfo->evregion.init = 1;
459     }
460
461         if (err != Success)
462         {
463         table = malloc (sizeof(EvlogAtomTable));
464         if (!table)
465             return reply;
466
467         table->xid = region;
468
469         snprintf (table->buf, XDBG_BUF_SIZE, "0x%lx", region);
470         xorg_list_add(&table->link, &evinfo->evregion.list);
471         evinfo->evregion.size++;
472     }
473     else
474     {
475         nrect = RegionNumRects(pRegion);
476         rects = RegionRects(pRegion);
477
478         for (i = 0; i < nrect; i++)
479         {
480             table = malloc (sizeof(EvlogAtomTable));
481             if (!table)
482                 return reply;
483
484             table->xid = region;
485
486             s = 0;
487             s += snprintf (table->buf + s, XDBG_BUF_SIZE - s,
488                            "[%d,%d %dx%d]",
489                                rects[i].x1,
490                                rects[i].y1,
491                                rects[i].x2 - rects[i].x1,
492                                rects[i].y2 - rects[i].y1);
493             xorg_list_add(&table->link, &evinfo->evregion.list);
494             evinfo->evregion.size++;
495         }
496     }
497
498 #endif
499     REPLY("(");
500     xorg_list_for_each_entry(table, &evinfo->evregion.list, link)
501         if(table->xid == region)
502         {
503             REPLY ("%s", table->buf);
504             if(table != xorg_list_last_entry(&evinfo->evregion.list, EvlogRegionTable, link))
505                 REPLY (", ");
506         }
507     REPLY(")");
508
509     return reply;
510 }