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