tizen 2.3 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
289     return rulechecker_validate_rule (rc,
290                                       evinfo->type,
291                                       evinfo->req.id,
292                                       evlog_name,
293                                       evinfo->client.pid,
294                                       cmd);
295 }
296
297 Bool
298 xDbgEvlogReadRuleFile(const char *filename, char *reply, int *len)
299 {
300     int   fd = -1;
301     char  fs[8096];
302     char *pfs;
303     int   rule_len;
304
305     fd = open (filename, O_RDONLY);
306     if (fd < 0)
307     {
308         REPLY ("failed: open '%s'. (%s)\n", filename, strerror(errno));
309         return FALSE;
310     }
311
312     rule_len = read(fd, fs, sizeof(fs));
313     pfs = fs;
314
315     while (pfs - fs < rule_len)
316     {
317         int   new_argc = 3;
318         char *new_argv[3] = {"add", };
319         char  policy[64] = {0, };
320         char  rule[1024] = {0, };
321         int   i;
322
323         if (pfs[0] == ' ' || pfs[0] == '\n')
324         {
325             pfs++;
326             continue;
327         }
328         for (i = 0 ; pfs[i] != ' ' ; i++)
329             policy[i] = pfs[i];
330
331         new_argv[1] = policy;
332         pfs += (strlen(new_argv[1]) + 1);
333
334         memset(rule, 0, sizeof(rule));
335         for (i = 0 ; pfs[i] != '\n' ; i++)
336             rule[i] = pfs[i];
337
338         new_argv[2] = rule;
339
340         pfs += (strlen(new_argv[2]) + 1);
341
342         if(!xDbgEvlogRuleSet ((const int) new_argc, (const char**) new_argv, reply, len))
343         {
344             if (fd >= 0)
345                 close (fd);
346
347             return FALSE;
348         }
349     }
350
351     if (fd >= 0)
352         close (fd);
353
354     return TRUE;
355 }
356
357 ExtensionInfo Evlog_extensions[] = {
358     {xDbgEvlogCompositeGetBase, 0, 0, 0, NULL, NULL},
359     {xDbgEvlogDamageGetBase, 0, 0, 0, NULL, NULL},
360     {xDbgEvlogDri2GetBase, 0, 0, 0, NULL, NULL},
361     {xDbgEvlogGestureGetBase, 0, 0, 0, NULL, NULL},
362     {xDbgEvlogXinputGetBase, 0, 0, 0, NULL, NULL},
363     {xDbgEvlogRandrGetBase, 0, 0, 0, NULL, NULL},
364     {xDbgEvlogXextDpmsGetBase, 0, 0, 0, NULL, NULL},
365     {xDbgEvlogXextShmGetBase, 0, 0, 0, NULL, NULL},
366     {xDbgEvlogXextSyncGetBase, 0, 0, 0, NULL, NULL},
367     {xDbgEvlogXextXtestGetBase, 0, 0, 0, NULL, NULL},
368     {xDbgEvlogXextXtestExt1GetBase, 0, 0, 0, NULL, NULL},
369     {xDbgEvlogXextShapeGetBase, 0, 0, 0, NULL, NULL},
370     {xDbgEvlogXvGetBase, 0, 0, 0, NULL, NULL},
371 #if HAVE_HWC
372     {xDbgEvlogHwcGetBase, 0, 0, 0, NULL, NULL},
373 #endif
374 };
375
376 ExtensionInfo* Sorted_Evlog_extensions;
377 int Extensions_size = 0;
378
379 static void
380 _ExtensionsSwap(ExtensionInfo* first, ExtensionInfo* second)
381 {
382     ExtensionInfo temp;
383
384     temp = *first ;
385     *first = *second ;
386     *second = temp ;
387 }
388
389 static Bool
390 _SortEvlogExtensions ()
391 {
392     int i,j;
393     int swap;
394
395     Sorted_Evlog_extensions = (ExtensionInfo*)malloc(sizeof(Evlog_extensions));
396     RETURN_VAL_IF_FAIL (Sorted_Evlog_extensions != NULL, FALSE);
397
398     memcpy(Sorted_Evlog_extensions, Evlog_extensions, sizeof(Evlog_extensions));
399
400     for (i = 0 ; i < Extensions_size - 1 ; i++)
401     {
402         swap = 0;
403         for (j = 1 ; j < Extensions_size - i ; j++)
404         {
405             if(Sorted_Evlog_extensions[j-1].evt_base > Sorted_Evlog_extensions[j].evt_base)
406             {
407                 _ExtensionsSwap(&Sorted_Evlog_extensions[j-1], &Sorted_Evlog_extensions[j]);
408                 swap = 1;
409             }
410         }
411         if (!swap) break;
412     }
413
414     return TRUE;
415 }
416
417
418 Bool
419 xDbgEvlogGetExtensionEntry ()
420 {
421     static int init = 0;
422     static Bool success = FALSE;
423     int i;
424
425     if (init)
426         return success;
427
428     init = 1;
429     Extensions_size = sizeof(Evlog_extensions) / sizeof (ExtensionInfo);
430
431     for (i = 0 ; i < Extensions_size ; i++)
432     {
433         Evlog_extensions[i].get_base_func (Evlog_extensions + i);
434     }
435
436     if(!_SortEvlogExtensions ())
437         return FALSE;
438
439
440     success = TRUE;
441
442     return success;
443 }
444
445
446 Bool
447 xDbgEvlogFillLog (EvlogInfo *evinfo, int detail_level, char *reply, int *len)
448 {
449     static CARD32 prev;
450
451     RETURN_VAL_IF_FAIL (evinfo->type >= 0 && (sizeof (evt_dir) / sizeof (char*)), FALSE);
452     RETURN_VAL_IF_FAIL (evinfo->type >= 0 && (sizeof (evt_type) / sizeof (char*)), FALSE);
453
454     if (evinfo->type == REPLY && !evinfo->rep.isStart)
455     {
456         if (detail_level >= EVLOG_PRINT_REPLY_DETAIL)
457             REPLY ("%67s"," ");
458         else
459             return FALSE;
460     }
461     else
462         REPLY ("[%10.3f][%5ld] %22s(%2d:%5d) %s %7s ",
463                     evinfo->time / 1000.0,
464                     (long int)evinfo->time - prev,
465                     xDbgEvlogGetCmd (evinfo->client.command),
466                     evinfo->client.index,
467                     evinfo->client.pid,
468                     evt_dir[evinfo->type],
469                     evt_type[evinfo->type]);
470
471     if (evinfo->type == REQUEST)
472     {
473         REPLY ("(");
474         reply = xDbgEvlogReqeust (evinfo, detail_level, reply, len);
475         REPLY (")");
476     }
477     else if (evinfo->type == EVENT)
478     {
479         evinfo->evt.size = sizeof (xEvent);
480         REPLY ("(");
481         reply = xDbgEvlogEvent (evinfo, detail_level, reply, len);
482         REPLY (")");
483     }
484     else if (evinfo->type == REPLY)
485     {
486         REPLY ("(");
487         reply = xDbgEvlogReply (evinfo, detail_level, reply, len);
488         REPLY (")");
489     }
490     else if (evinfo->type == ERROR)
491     {
492         REPLY("(ErrorCode(0x%02x) resourceID(0x%x) majorCode(%d) minorCode(%d))",
493             evinfo->err.errorCode,
494             (unsigned int)evinfo->err.resourceID,
495             evinfo->err.majorCode,
496             evinfo->err.minorCode);
497     }
498     else
499     {
500         const char *evlog_name = "";
501         if (evinfo->type == REQUEST)
502             evlog_name = evinfo->req.name;
503         else if (evinfo->type == EVENT)
504             evlog_name = evinfo->evt.name;
505         else if (evinfo->type == REPLY)
506             evlog_name = evinfo->rep.name;
507         REPLY ("(%s)", evlog_name);
508     }
509
510     REPLY ("\n");
511
512     prev = evinfo->time;
513
514     return TRUE;
515 }
516
517
518 void xDbgDistroyAtomList (EvlogInfo *evinfo)
519 {
520     EvlogAtomTable *cur = NULL, *next = NULL;
521
522     if (!evinfo->evatom.init)
523         return;
524
525     xorg_list_for_each_entry_safe(cur, next, &evinfo->evatom.list, link)
526     {
527         xorg_list_del(&cur->link);
528         free (cur);
529         cur = NULL;
530     }
531     evinfo->evatom.init = 0;
532     evinfo->evatom.size = 0;
533 }
534
535 void xDbgDistroyRegionList (EvlogInfo *evinfo)
536 {
537     EvlogRegionTable *cur = NULL, *next = NULL;
538
539     if (!evinfo->evregion.init)
540         return;
541
542     xorg_list_for_each_entry_safe(cur, next, &evinfo->evregion.list, link)
543     {
544         xorg_list_del(&cur->link);
545         free (cur);
546         cur = NULL;
547     }
548     evinfo->evregion.init = 0;
549     evinfo->evregion.size = 0;
550 }
551
552 char* xDbgGetAtom(Atom atom, EvlogInfo *evinfo, char *reply, int *len)
553 {
554     EvlogAtomTable *table;
555 #ifndef XDBG_CLIENT
556     table = malloc (sizeof(EvlogAtomTable));
557     if (!table)
558         return reply;
559
560     evinfo->mask |= EVLOG_MASK_ATOM;
561     table->xid = atom;
562
563     if (!evinfo->evatom.init)
564     {
565         xorg_list_init(&evinfo->evatom.list);
566         evinfo->evatom.init = 1;
567     }
568
569     if (NameForAtom(atom))
570         snprintf (table->buf, XDBG_BUF_SIZE, "%s", (char*)NameForAtom(atom));
571     else
572         snprintf (table->buf, XDBG_BUF_SIZE, "0x%x", (unsigned int)atom);
573
574     xorg_list_add(&table->link, &evinfo->evatom.list);
575     evinfo->evatom.size++;
576 #endif
577     xorg_list_for_each_entry(table, &evinfo->evatom.list, link)
578         if(table->xid == atom)
579         {
580             REPLY ("(%s)", table->buf);
581             break;
582         }
583
584     return reply;
585 }
586
587 char* xDbgGetRegion(XserverRegion region, EvlogInfo *evinfo, char *reply, int *len)
588 {
589     EvlogRegionTable *table;
590 #ifndef XDBG_CLIENT
591     extern _X_EXPORT RESTYPE RegionResType;
592     RegionPtr pRegion;
593     BoxPtr rects;
594     int nrect, i;
595     int s;
596     int err = dixLookupResourceByType((pointer *) &pRegion, region,
597                                        RegionResType, (ClientPtr)evinfo->client.pClient,
598                                        DixReadAccess);
599
600     evinfo->mask |= EVLOG_MASK_REGION;
601
602     if (!evinfo->evregion.init)
603     {
604         xorg_list_init(&evinfo->evregion.list);
605         evinfo->evregion.init = 1;
606     }
607
608         if (err != Success)
609         {
610         table = malloc (sizeof(EvlogAtomTable));
611         if (!table)
612             return reply;
613
614         table->xid = region;
615
616         snprintf (table->buf, XDBG_BUF_SIZE, "0x%x", (unsigned int)region);
617         xorg_list_add(&table->link, &evinfo->evregion.list);
618         evinfo->evregion.size++;
619     }
620     else
621     {
622         nrect = RegionNumRects(pRegion);
623         rects = RegionRects(pRegion);
624
625         for (i = 0; i < nrect; i++)
626         {
627             table = malloc (sizeof(EvlogAtomTable));
628             if (!table)
629                 return reply;
630
631             table->xid = region;
632
633             s = 0;
634             s += snprintf (table->buf + s, XDBG_BUF_SIZE - s,
635                            "[%d,%d %dx%d]",
636                                rects[i].x1,
637                                rects[i].y1,
638                                rects[i].x2 - rects[i].x1,
639                                rects[i].y2 - rects[i].y1);
640             xorg_list_add(&table->link, &evinfo->evregion.list);
641             evinfo->evregion.size++;
642         }
643     }
644
645 #endif
646     REPLY("(");
647     xorg_list_for_each_entry(table, &evinfo->evregion.list, link)
648         if(table->xid == region)
649         {
650             REPLY ("%s", table->buf);
651             if(table != xorg_list_last_entry(&evinfo->evregion.list, EvlogRegionTable, link))
652                 REPLY (", ");
653         }
654     REPLY(")");
655
656     return reply;
657 }