tizen 2.4 release
[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 <config.h>
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <sys/types.h>
38 #include <sys/fcntl.h>
39 #include <unistd.h>
40 #include <stdarg.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <time.h>
44 #include <X11/Xlib.h>
45
46 #include "xdbg_types.h"
47 #include "xdbg_evlog.h"
48 #include "bool_exp_rule_checker.h"
49 #include <X11/Xlibint.h>
50
51 #ifndef XDBG_CLIENT
52 #include "resource.h"
53 #include "region.h"
54 #include "dix.h"
55 #endif
56
57 static char *evt_type[] = { "Event", "Request", "Reply", "Flush", "Error" ""};
58 static char *evt_dir[]  = { "<====", "---->",   "<----", "*****", "<----", ""};
59
60 static RULE_CHECKER rc = NULL;
61
62 static void
63 _mergeArgs (char *target, int target_size, int argc, const char ** argv)
64 {
65     int i;
66     int len;
67
68     for (i=0; i<argc; i++)
69     {
70         len = snprintf (target, target_size, "%s", argv[i]);
71         target += len;
72         target_size -= len;
73
74         if (i != argc - 1)
75         {
76             *(target++) = ' ';
77             target_size--;
78         }
79     }
80 }
81
82 static int
83 _strcasecmp(const char *str1, const char *str2)
84 {
85     const u_char *us1 = (const u_char *) str1, *us2 = (const u_char *) str2;
86
87     while (tolower(*us1) == tolower(*us2)) {
88         if (*us1++ == '\0')
89             return 0;
90         us2++;
91     }
92
93     return (tolower(*us1) - tolower(*us2));
94 }
95
96 char*
97 xDbgEvlogGetCmd (char *path)
98 {
99     char *p;
100     if (!path)
101         return NULL;
102     p = strrchr (path, '/');
103     return (p)?p+1:path;
104 }
105
106 Bool
107 xDbgEvlogRuleSet (const int argc, const char **argv, char *reply, int *len)
108 {
109     const char * command;
110
111     if (rc == NULL)
112         rc = rulechecker_init();
113
114     if (argc == 0)
115     {
116         rulechecker_print_rule (rc, reply, len);
117         return TRUE;
118     }
119
120     command = argv[0];
121
122     if (!_strcasecmp (command, "add"))
123     {
124         POLICY_TYPE policy_type;
125         RC_RESULT_TYPE result;
126         const char * policy = argv[1];
127         char merge[8192]={0,}, rule[8192]={0,};
128         int i, index = 0, size_rule;
129         int apply = 0;
130
131         if (argc < 3)
132         {
133             REPLY ("Error : Too few arguments.\n");
134             return FALSE;
135         }
136
137         if (!_strcasecmp (policy, "ALLOW"))
138             policy_type = ALLOW;
139         else if (!_strcasecmp (policy, "DENY"))
140             policy_type = DENY;
141         else
142         {
143             REPLY ("Error : Unknown policy : [%s].\n          Policy should be ALLOW or DENY.\n", policy);
144             return FALSE;
145         }
146
147         _mergeArgs (merge, sizeof (merge), argc - 2, &(argv[2]));
148
149         size_rule = sizeof (rule) - 1;
150
151         for (i = 0 ; i < strlen(merge) ; i++)
152         {
153             if(merge[i] == '\"' || merge[i] == '\'')
154             {
155                 rule[index++] = ' ';
156                 if (index > size_rule)
157                     return FALSE;
158
159                 continue;
160             }
161
162             if(merge[i] == '+')
163             {
164                 rule[index++] = ' ';
165                 if (index > size_rule)
166                     return FALSE;
167
168                 if (apply == 0)
169                 {
170                     const char* plus = "|| type=reply || type=error";
171                     int len = MIN (size_rule - index, strlen(plus));
172                     strncat(rule, plus, len);
173                     index += len;
174                     if (index > size_rule)
175                         return FALSE;
176
177                     apply = 1;
178                 }
179                 continue;
180             }
181             rule[index++] = merge[i];
182             if (index > size_rule)
183                 return FALSE;
184         }
185
186         result = rulechecker_add_rule (rc, policy_type, rule);
187         if (result == RC_ERR_TOO_MANY_RULES)
188         {
189             REPLY ("Error : Too many rules were added.\n");
190             return FALSE;
191         }
192         else if (result == RC_ERR_PARSE_ERROR)
193         {
194             REPLY ("Error : An error occured during parsing the rule [%s]\n", rule);
195             return FALSE;
196         }
197
198         REPLY ("The rule was successfully added.\n\n");
199         rulechecker_print_rule (rc, reply, len);
200         return TRUE;
201     }
202     else if (!_strcasecmp (command, "remove"))
203     {
204         const char * remove_idx;
205         int i;
206
207         if (argc < 2)
208         {
209             REPLY ("Error : Too few arguments.\n");
210             return FALSE;
211         }
212
213         for (i=0; i<argc - 1; i++)
214         {
215             remove_idx = argv[i+1];
216
217             if (!_strcasecmp (remove_idx, "all"))
218             {
219                 rulechecker_destroy (rc);
220                 rc = rulechecker_init();
221                 REPLY ("Every rules were successfully removed.\n");
222             }
223             else
224             {
225                 int index = atoi (remove_idx);
226                 if (isdigit (*remove_idx) && rulechecker_remove_rule (rc, index) == 0)
227                     REPLY ("The rule [%d] was successfully removed.\n", index);
228                 else
229                     REPLY ("Rule remove fail : No such rule [%s].\n", remove_idx);
230             }
231         }
232         rulechecker_print_rule (rc, reply, len);
233         return TRUE;
234     }
235     else if (!_strcasecmp (command, "file"))
236     {
237         if (argc < 2)
238         {
239             REPLY ("Error : Too few arguments.\n");
240             return FALSE;
241         }
242
243         if (!xDbgEvlogReadRuleFile(argv[1], reply, len))
244             return FALSE;
245         rulechecker_print_rule (rc, reply, len);
246
247         return TRUE;
248     }
249     else if (!_strcasecmp (command, "print"))
250     {
251         rulechecker_print_rule (rc, reply, len);
252         return TRUE;
253     }
254     else if (!_strcasecmp (command, "help"))
255     {
256         REPLY ("%s", rulechecker_print_usage());
257         return TRUE;
258     }
259
260     REPLY ("%s\nUnknown command : [%s].\n\n", rulechecker_print_usage(), command);
261
262     return TRUE;
263 }
264
265 Bool
266 xDbgEvlogRuleValidate (EvlogInfo *evinfo)
267 {
268     const char *evlog_name = "";
269     char *cmd = "";
270
271     if (rc == NULL)
272         rc = rulechecker_init ();
273
274     if (!rc)
275     {
276         XDBG_LOG ("failed: create rulechecker\n");
277         return FALSE;
278     }
279
280     cmd = xDbgEvlogGetCmd (evinfo->client.command);
281
282     if (evinfo->type == REQUEST)
283         evlog_name = evinfo->req.name;
284     else if (evinfo->type == EVENT)
285         evlog_name = evinfo->evt.name;
286     else if (evinfo ->type == REPLY)
287         evlog_name = evinfo->rep.name;
288     else if (evinfo ->type == XERROR)
289         return TRUE;
290
291     return rulechecker_validate_rule (rc,
292                                       evinfo->type,
293                                       evinfo->req.id,
294                                       evlog_name,
295                                       evinfo->client.pid,
296                                       cmd);
297 }
298
299 Bool
300 xDbgEvlogReadRuleFile(const char *filename, char *reply, int *len)
301 {
302     int   fd = -1;
303     char  fs[8096];
304     char *pfs;
305     int   rule_len;
306
307     fd = open (filename, O_RDONLY);
308     if (fd < 0)
309     {
310         char err_buf[256] = {0,};
311         char *errp;
312
313         errp = (char *)strerror_r (errno, err_buf, sizeof(err_buf));
314         REPLY ("failed: open '%s'. (%s)\n", filename, errp);
315         return FALSE;
316     }
317
318     rule_len = read(fd, fs, sizeof(fs));
319     pfs = fs;
320
321     while (pfs - fs < rule_len)
322     {
323         int   new_argc = 3;
324         char *new_argv[3] = {"add", };
325         char  policy[64] = {0, };
326         char  rule[1024] = {0, };
327         int   i;
328
329         if (pfs[0] == ' ' || pfs[0] == '\n')
330         {
331             pfs++;
332             continue;
333         }
334         for (i = 0 ; pfs[i] != ' ' ; i++)
335             policy[i] = pfs[i];
336
337         new_argv[1] = policy;
338         pfs += (strlen(new_argv[1]) + 1);
339
340         memset(rule, 0, sizeof(rule));
341         for (i = 0 ; pfs[i] != '\n' ; i++)
342             rule[i] = pfs[i];
343
344         new_argv[2] = rule;
345
346         pfs += (strlen(new_argv[2]) + 1);
347
348         if(!xDbgEvlogRuleSet ((const int) new_argc, (const char**) new_argv, reply, len))
349         {
350             if (fd >= 0)
351                 close (fd);
352
353             return FALSE;
354         }
355     }
356
357     if (fd >= 0)
358         close (fd);
359
360     return TRUE;
361 }
362
363 ExtensionInfo Evlog_extensions[] = {
364     {xDbgEvlogCompositeGetBase, 0, 0, 0, NULL, NULL},
365     {xDbgEvlogDamageGetBase, 0, 0, 0, NULL, NULL},
366     {xDbgEvlogDri2GetBase, 0, 0, 0, NULL, NULL},
367     {xDbgEvlogGestureGetBase, 0, 0, 0, NULL, NULL},
368     {xDbgEvlogXinputGetBase, 0, 0, 0, NULL, NULL},
369     {xDbgEvlogRandrGetBase, 0, 0, 0, NULL, NULL},
370     {xDbgEvlogXextDpmsGetBase, 0, 0, 0, NULL, NULL},
371     {xDbgEvlogXextShmGetBase, 0, 0, 0, NULL, NULL},
372     {xDbgEvlogXextSyncGetBase, 0, 0, 0, NULL, NULL},
373     {xDbgEvlogXextXtestGetBase, 0, 0, 0, NULL, NULL},
374     {xDbgEvlogXextXtestExt1GetBase, 0, 0, 0, NULL, NULL},
375     {xDbgEvlogXextShapeGetBase, 0, 0, 0, NULL, NULL},
376     {xDbgEvlogXvGetBase, 0, 0, 0, NULL, NULL},
377     {xDbgEvlogDri3GetBase, 0, 0, 0, NULL, NULL},
378     {xDbgEvlogPresentGetBase, 0, 0, 0, NULL, NULL},
379 #if HAVE_HWC
380     {xDbgEvlogHwcGetBase, 0, 0, 0, NULL, NULL},
381 #endif
382 };
383
384 ExtensionInfo* Sorted_Evlog_extensions;
385 int Extensions_size = 0;
386
387 static void
388 _ExtensionsSwap(ExtensionInfo* first, ExtensionInfo* second)
389 {
390     ExtensionInfo temp;
391
392     temp = *first ;
393     *first = *second ;
394     *second = temp ;
395 }
396
397 static Bool
398 _SortEvlogExtensions ()
399 {
400     int i,j;
401     int swap;
402
403     Sorted_Evlog_extensions = (ExtensionInfo*)malloc(sizeof(Evlog_extensions));
404     RETURN_VAL_IF_FAIL (Sorted_Evlog_extensions != NULL, FALSE);
405
406     memcpy(Sorted_Evlog_extensions, Evlog_extensions, sizeof(Evlog_extensions));
407
408     for (i = 0 ; i < Extensions_size - 1 ; i++)
409     {
410         swap = 0;
411         for (j = 1 ; j < Extensions_size - i ; j++)
412         {
413             if(Sorted_Evlog_extensions[j-1].evt_base > Sorted_Evlog_extensions[j].evt_base)
414             {
415                 _ExtensionsSwap(&Sorted_Evlog_extensions[j-1], &Sorted_Evlog_extensions[j]);
416                 swap = 1;
417             }
418         }
419         if (!swap) break;
420     }
421
422     return TRUE;
423 }
424
425
426 Bool
427 xDbgEvlogGetExtensionEntry ()
428 {
429     static int init = 0;
430     static Bool success = FALSE;
431     int i;
432
433     if (init)
434         return success;
435
436     init = 1;
437     Extensions_size = sizeof(Evlog_extensions) / sizeof (ExtensionInfo);
438
439     for (i = 0 ; i < Extensions_size ; i++)
440     {
441         Evlog_extensions[i].get_base_func (Evlog_extensions + i);
442     }
443
444     if(!_SortEvlogExtensions ())
445         return FALSE;
446
447
448     success = TRUE;
449
450     return success;
451 }
452
453
454 Bool
455 xDbgEvlogFillLog (EvlogInfo *evinfo, int detail_level, char *reply, int *len)
456 {
457     static CARD32 prev;
458
459     RETURN_VAL_IF_FAIL (evinfo->type >= 0 && (sizeof (evt_dir) / sizeof (char*)), FALSE);
460     RETURN_VAL_IF_FAIL (evinfo->type >= 0 && (sizeof (evt_type) / sizeof (char*)), FALSE);
461
462     if (evinfo->type == REPLY && !evinfo->rep.isStart)
463     {
464         if (detail_level >= EVLOG_PRINT_REPLY_DETAIL)
465             REPLY ("%67s"," ");
466         else
467             return FALSE;
468     }
469     else
470         REPLY ("[%10.3f][%5ld] %22s(%2d:%5d) %s %7s ",
471                     evinfo->time / 1000.0,
472                     (long int)evinfo->time - prev,
473                     xDbgEvlogGetCmd (evinfo->client.command),
474                     evinfo->client.index,
475                     evinfo->client.pid,
476                     evt_dir[evinfo->type],
477                     evt_type[evinfo->type]);
478
479     if (evinfo->type == REQUEST)
480     {
481         REPLY ("(");
482         reply = xDbgEvlogReqeust (evinfo, detail_level, reply, len);
483         REPLY (")");
484     }
485     else if (evinfo->type == EVENT)
486     {
487         evinfo->evt.size = sizeof (xEvent);
488         REPLY ("(");
489         reply = xDbgEvlogEvent (evinfo, detail_level, reply, len);
490         REPLY (")");
491     }
492     else if (evinfo->type == REPLY)
493     {
494         REPLY ("(");
495         reply = xDbgEvlogReply (evinfo, detail_level, reply, len);
496         REPLY (")");
497     }
498     else if (evinfo->type == ERROR || evinfo->type == XERROR)
499     {
500         REPLY("(%s:ErrorCode(0x%02x) %s:majorCode(%d) minorCode(%d) resourceID(0x%x))",
501             evinfo->err.errorName,
502             evinfo->err.errorCode,
503             evinfo->err.majorName,
504             evinfo->err.majorCode,
505             evinfo->err.minorCode,
506             (unsigned int)evinfo->err.resourceID);
507     }
508     else
509     {
510         const char *evlog_name = "";
511         if (evinfo->type == REQUEST)
512             evlog_name = evinfo->req.name;
513         else if (evinfo->type == EVENT)
514             evlog_name = evinfo->evt.name;
515         else if (evinfo->type == REPLY)
516             evlog_name = evinfo->rep.name;
517         REPLY ("(%s)", evlog_name);
518     }
519
520     REPLY ("\n");
521
522     prev = evinfo->time;
523
524     return TRUE;
525 }
526
527
528 void xDbgDistroyAtomList (EvlogInfo *evinfo)
529 {
530     EvlogAtomTable *cur = NULL, *next = NULL;
531
532     if (!evinfo->evatom.init)
533         return;
534
535     xorg_list_for_each_entry_safe(cur, next, &evinfo->evatom.list, link)
536     {
537         xorg_list_del(&cur->link);
538         free (cur);
539         cur = NULL;
540     }
541     evinfo->evatom.init = 0;
542     evinfo->evatom.size = 0;
543 }
544
545 void xDbgDistroyRegionList (EvlogInfo *evinfo)
546 {
547     EvlogRegionTable *cur = NULL, *next = NULL;
548
549     if (!evinfo->evregion.init)
550         return;
551
552     xorg_list_for_each_entry_safe(cur, next, &evinfo->evregion.list, link)
553     {
554         xorg_list_del(&cur->link);
555         free (cur);
556         cur = NULL;
557     }
558     evinfo->evregion.init = 0;
559     evinfo->evregion.size = 0;
560 }
561
562 char* xDbgGetAtom(Atom atom, EvlogInfo *evinfo, char *reply, int *len)
563 {
564     EvlogAtomTable *table;
565 #ifndef XDBG_CLIENT
566     table = malloc (sizeof(EvlogAtomTable));
567     if (!table)
568         return reply;
569
570     evinfo->mask |= EVLOG_MASK_ATOM;
571     table->xid = atom;
572
573     if (!evinfo->evatom.init)
574     {
575         xorg_list_init(&evinfo->evatom.list);
576         evinfo->evatom.init = 1;
577     }
578
579     if (NameForAtom(atom))
580         snprintf (table->buf, XDBG_BUF_SIZE, "%s", (char*)NameForAtom(atom));
581     else
582         snprintf (table->buf, XDBG_BUF_SIZE, "0x%x", (unsigned int)atom);
583
584     xorg_list_add(&table->link, &evinfo->evatom.list);
585     evinfo->evatom.size++;
586 #endif
587     xorg_list_for_each_entry(table, &evinfo->evatom.list, link)
588         if(table->xid == atom)
589         {
590             REPLY ("(%s)", table->buf);
591             break;
592         }
593
594     return reply;
595 }
596
597 char* xDbgGetRegion(XserverRegion region, EvlogInfo *evinfo, char *reply, int *len)
598 {
599     EvlogRegionTable *table;
600 #ifndef XDBG_CLIENT
601     extern _X_EXPORT RESTYPE RegionResType;
602     RegionPtr pRegion;
603     BoxPtr rects;
604     int nrect, i;
605     int s;
606     int err = dixLookupResourceByType((pointer *) &pRegion, region,
607                                        RegionResType, (ClientPtr)evinfo->client.pClient,
608                                        DixReadAccess);
609
610     evinfo->mask |= EVLOG_MASK_REGION;
611
612     if (!evinfo->evregion.init)
613     {
614         xorg_list_init(&evinfo->evregion.list);
615         evinfo->evregion.init = 1;
616     }
617
618         if (err != Success)
619         {
620         table = malloc (sizeof(EvlogAtomTable));
621         if (!table)
622             return reply;
623
624         table->xid = region;
625
626         snprintf (table->buf, XDBG_BUF_SIZE, "0x%x", (unsigned int)region);
627         xorg_list_add(&table->link, &evinfo->evregion.list);
628         evinfo->evregion.size++;
629     }
630     else
631     {
632         nrect = RegionNumRects(pRegion);
633         rects = RegionRects(pRegion);
634
635         for (i = 0; i < nrect; i++)
636         {
637             table = malloc (sizeof(EvlogAtomTable));
638             if (!table)
639                 return reply;
640
641             table->xid = region;
642
643             s = 0;
644             s += snprintf (table->buf + s, XDBG_BUF_SIZE - s,
645                            "[%d,%d %dx%d]",
646                                rects[i].x1,
647                                rects[i].y1,
648                                rects[i].x2 - rects[i].x1,
649                                rects[i].y2 - rects[i].y1);
650             xorg_list_add(&table->link, &evinfo->evregion.list);
651             evinfo->evregion.size++;
652         }
653     }
654
655 #endif
656     REPLY("(");
657     xorg_list_for_each_entry(table, &evinfo->evregion.list, link)
658         if(table->xid == region)
659         {
660             REPLY ("%s", table->buf);
661             if(table != xorg_list_last_entry(&evinfo->evregion.list, EvlogRegionTable, link))
662                 REPLY (", ");
663         }
664     REPLY(")");
665
666     return reply;
667 }